Skip to content

Commit 023e7f4

Browse files
committed
feat: Add BiliBili player compoment.
1 parent f7f1aab commit 023e7f4

File tree

2 files changed

+185
-0
lines changed

2 files changed

+185
-0
lines changed

docs/.vuepress/client.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import ElementPlus from 'element-plus'
1010
import 'element-plus/dist/index.css'
1111
import 'instantsearch.css/themes/algolia-min.css'
1212
import InstantSearch from 'vue-instantsearch/vue3/es/index.js'
13+
import BiliBiliPlayer from './components/BiliBili.vue'
1314

1415
export default defineClientConfig({
1516
enhance({ app, router, siteData }) {
@@ -19,6 +20,7 @@ export default defineClientConfig({
1920
app.component('Link', Link)
2021
app.component('ImageGallery', ImageGallery)
2122
app.component('ImageItem', ImageItem)
23+
app.component('BiliBiliPlayer', BiliBiliPlayer)
2224
app.use(InstantSearch)
2325
},
2426
setup() {},
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
<template>
2+
<div v-if="videoLink">
3+
<div class="bilibili-desc">
4+
<a class="sr-only" :href="videoLink">{{ title }}</a>
5+
</div>
6+
<iframe
7+
ref="el"
8+
:src="videoLink"
9+
:title="title"
10+
class="bilibili-iframe"
11+
:allow="videoIframeAllow"
12+
:style="{ width: width, height: loaded ? computedHeight : '0' }"
13+
@load="onLoad"
14+
/>
15+
<div v-if="!loaded">
16+
<svg
17+
xmlns="http://www.w3.org/2000/svg"
18+
width="32"
19+
height="32"
20+
preserveAspectRatio="xMidYMid"
21+
viewBox="0 0 100 100"
22+
>
23+
<circle cx="28" cy="75" r="11" fill="currentColor">
24+
<animate
25+
attributeName="fill-opacity"
26+
begin="0s"
27+
dur="1s"
28+
keyTimes="0;0.2;1"
29+
repeatCount="indefinite"
30+
values="0;1;1"
31+
/>
32+
</circle>
33+
<path
34+
fill="none"
35+
stroke="#88baf0"
36+
stroke-width="10"
37+
d="M28 47a28 28 0 0 1 28 28"
38+
>
39+
<animate
40+
attributeName="stroke-opacity"
41+
begin="0.1s"
42+
dur="1s"
43+
keyTimes="0;0.2;1"
44+
repeatCount="indefinite"
45+
values="0;1;1"
46+
/>
47+
</path>
48+
<path
49+
fill="none"
50+
stroke="#88baf0"
51+
stroke-width="10"
52+
d="M28 25a50 50 0 0 1 50 50"
53+
>
54+
<animate
55+
attributeName="stroke-opacity"
56+
begin="0.2s"
57+
dur="1s"
58+
keyTimes="0;0.2;1"
59+
repeatCount="indefinite"
60+
values="0;1;1"
61+
/>
62+
</path>
63+
</svg>
64+
</div>
65+
</div>
66+
</template>
67+
68+
<script lang="ts">
69+
import { computed, defineComponent, ref, onMounted, onBeforeUnmount } from 'vue'
70+
const VIDEO_LINK = 'https://player.bilibili.com/player.html'
71+
72+
export default defineComponent({
73+
name: 'BiliBili',
74+
75+
props: {
76+
bvid: {
77+
type: String,
78+
default: ''
79+
},
80+
aid: {
81+
type: String,
82+
default: ''
83+
},
84+
cid: {
85+
type: String,
86+
default: ''
87+
},
88+
title: {
89+
type: String,
90+
default: 'A BiliBili video'
91+
},
92+
page: {
93+
type: [String, Number],
94+
default: 1
95+
},
96+
width: {
97+
type: [String, Number],
98+
default: '100%'
99+
},
100+
height: {
101+
type: [String, Number],
102+
default: `${100 / (16 / 9)}vh`
103+
},
104+
ratio: {
105+
type: [String, Number],
106+
default: 16 / 9
107+
},
108+
time: {
109+
type: [String, Number],
110+
default: 0
111+
},
112+
autoplay: Boolean
113+
},
114+
115+
setup(props) {
116+
const loaded = ref(false)
117+
const el = ref<HTMLElement | null>(null)
118+
const videoIframeAllow =
119+
'accelerometer; autoplay; clipboard-write; encrypted-media; fullscreen; gyroscope; picture-in-picture'
120+
const videoLink = computed(() => {
121+
const { aid, bvid, cid, autoplay, time, page } = props
122+
123+
return aid && cid
124+
? `${VIDEO_LINK}?aid=${aid}&cid=${cid}&t=${time}&autoplay=${
125+
autoplay ? 1 : 0
126+
}&p=${page}`
127+
: bvid
128+
? `${VIDEO_LINK}?bvid=${bvid}&t=${time}&autoplay=${autoplay ? 1 : 0}`
129+
: null
130+
})
131+
132+
const computedHeight = ref('0px')
133+
134+
const updateHeight = () => {
135+
if (el.value) {
136+
const width = el.value.clientWidth
137+
computedHeight.value = `${width / (16 / 9)}px`
138+
}
139+
}
140+
141+
onMounted(() => {
142+
updateHeight()
143+
window.addEventListener('resize', updateHeight)
144+
})
145+
146+
onBeforeUnmount(() => {
147+
window.removeEventListener('resize', updateHeight)
148+
})
149+
150+
const onLoad = () => {
151+
loaded.value = true
152+
}
153+
154+
return {
155+
el,
156+
loaded,
157+
videoLink,
158+
computedHeight,
159+
onLoad,
160+
videoIframeAllow,
161+
title: props.title
162+
}
163+
}
164+
})
165+
</script>
166+
167+
<style scoped>
168+
.bilibili-desc a {
169+
@media print {
170+
display: block;
171+
}
172+
}
173+
174+
.bilibili-iframe {
175+
margin: 8px 0;
176+
border: none;
177+
border-radius: 8px;
178+
179+
@media print {
180+
display: none;
181+
}
182+
}
183+
</style>

0 commit comments

Comments
 (0)