Skip to content

Commit 18214cc

Browse files
feat: add support for YT.Player
1 parent c078079 commit 18214cc

File tree

4 files changed

+89
-5
lines changed

4 files changed

+89
-5
lines changed

demo/App.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ export default Vue.extend({
2828
player.stopVideo()
2929
}, 3000)
3030
},
31+
onPlayerInit(player: YT.Player) {
32+
console.log(player)
33+
},
3134
},
3235
render(h): VNode {
3336
return h('ul', {}, [
@@ -66,9 +69,12 @@ export default Vue.extend({
6669
webp: false,
6770
autoplay: true,
6871
iframeAttributes: this.iframeAttributes,
72+
enablejsapi: true,
73+
injectPlayerScript: true,
6974
},
7075
on: {
7176
'load:iframe': this.onIframeLoad,
77+
'init:player': this.onPlayerInit,
7278
},
7379
}),
7480
]),

src/VueLazyYoutubeVideo.ts

Lines changed: 77 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1-
import Vue, { PropType, VNode } from 'vue'
2-
import type { LoadIframeEventPayload } from './types'
1+
import Vue, { VueConstructor, PropType, VNode } from 'vue'
2+
import type { LoadIframeEventPayload, Refs } from './types'
33
import { startsWith } from './helpers'
4-
import { PREVIEW_IMAGE_SIZES, DEFAULT_IFRAME_ATTRIBUTES } from './constants'
4+
import {
5+
PREVIEW_IMAGE_SIZES,
6+
DEFAULT_IFRAME_ATTRIBUTES,
7+
PLAYER_SCRIPT_SRC,
8+
} from './constants'
59

6-
export default Vue.extend({
10+
export default (Vue as VueConstructor<Vue & { $refs: Refs }>).extend({
711
name: 'VueLazyYoutubeVideo',
812
props: {
913
src: {
@@ -52,10 +56,24 @@ export default Vue.extend({
5256
thumbnailListeners: {
5357
type: Object as PropType<Record<string, Function | Function[]>>,
5458
},
59+
enablejsapi: {
60+
type: Boolean,
61+
default: false,
62+
},
63+
playerOptions: {
64+
type: Object as PropType<YT.PlayerOptions>,
65+
default: () => ({}),
66+
},
67+
injectPlayerScript: {
68+
type: Boolean,
69+
default: false,
70+
},
5571
},
5672
data() {
5773
return {
5874
activated: this.autoplay,
75+
playerInstance: null as YT.Player | null,
76+
__interval__: null as NodeJS.Timeout | null,
5977
}
6078
},
6179
computed: {
@@ -72,7 +90,9 @@ export default Vue.extend({
7290
srcAttribute(): string {
7391
const hasQuestionMark =
7492
typeof this.src === 'string' && this.src.indexOf('?') !== -1
75-
return `${this.src}${hasQuestionMark ? '&' : '?'}autoplay=1`
93+
return `${this.src}${hasQuestionMark ? '&' : '?'}autoplay=1${
94+
this.enablejsapi ? '&enablejsapi=1' : ''
95+
}`
7696
},
7797
styleObj(): object {
7898
return {
@@ -113,10 +133,62 @@ export default Vue.extend({
113133
onIframeLoad() {
114134
const payload: LoadIframeEventPayload = { iframe: this.getIframe() }
115135
this.$emit('load:iframe', payload)
136+
137+
if (this.enablejsapi) {
138+
try {
139+
window.YT.Player
140+
this.initPlayerInstance()
141+
} catch (e) {
142+
if (this.injectPlayerScript) {
143+
this.doInjectPlayerScript()
144+
} else {
145+
console.error(
146+
'[vue-lazy-youtube-video]: window.YT.Player is not defined. Make sure you either included the IFrame Player API or passed `injectPlayerScript` prop'
147+
)
148+
throw e
149+
}
150+
}
151+
}
116152
},
117153
getIframe() {
118154
return this.$refs.iframe as HTMLIFrameElement | undefined
119155
},
156+
checkPlayer() {
157+
if (YT.Player) {
158+
if (this.__interval__) {
159+
clearInterval(this.__interval__)
160+
}
161+
162+
this.initPlayerInstance()
163+
return true
164+
}
165+
return false
166+
},
167+
initPlayerInstance() {
168+
const { iframe } = this.$refs
169+
if (!iframe)
170+
throw new Error(
171+
'[vue-lazy-youtube-video]: YT.Player can not be instantiated without iframe element'
172+
)
173+
this.playerInstance = new YT.Player(iframe, this.playerOptions)
174+
this.$emit('init:player', this.playerInstance)
175+
return this.playerInstance
176+
},
177+
getPlayerInstance() {
178+
return this.playerInstance
179+
},
180+
doInjectPlayerScript() {
181+
const script = document.createElement('script')
182+
script.setAttribute('src', PLAYER_SCRIPT_SRC)
183+
184+
script.onload = () => {
185+
this.__interval__ = setInterval(() => {
186+
this.checkPlayer()
187+
}, 32)
188+
}
189+
190+
document.head.appendChild(script)
191+
},
120192
warn(message: string) {
121193
console.warn(`[vue-lazy-youtube-video]: ${message}`)
122194
},

src/constants/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,5 @@ export const PREVIEW_IMAGE_SIZES = [
1212
'hqdefault',
1313
'maxresdefault',
1414
] as const
15+
16+
export const PLAYER_SCRIPT_SRC = 'https://www.youtube.com/player_api'

src/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
export interface LoadIframeEventPayload {
22
iframe?: HTMLIFrameElement
33
}
4+
5+
export interface Refs {
6+
iframe?: HTMLIFrameElement
7+
}

0 commit comments

Comments
 (0)