mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-25 08:01:20 -08:00
feat: Add support for dynamic thumbnails in Artplayer
The code changes introduce a new `art.thumbnails` property that allows for dynamic setting of thumbnails in Artplayer. This feature enhances the user experience by providing a visual preview of the video content.
This commit is contained in:
1 parent
5655db4b20
commit
52d9064c8b
10 files changed
+260
-110
No files matched your search
@@ -81,15 +81,13 @@ export default class Control extends Component {
|
||||
);
|
||||
}
|
||||
|
||||
if (option.thumbnails.url && !option.isLive) {
|
||||
this.add(
|
||||
thumbnails({
|
||||
name: 'thumbnails',
|
||||
position: 'top',
|
||||
index: 20,
|
||||
}),
|
||||
);
|
||||
}
|
||||
this.add(
|
||||
thumbnails({
|
||||
name: 'thumbnails',
|
||||
position: 'top',
|
||||
index: 20,
|
||||
}),
|
||||
);
|
||||
|
||||
this.add(
|
||||
playAndPause({
|
||||
|
||||
@@ -1,72 +1,8 @@
|
||||
import { setStyle, isMobile } from '../utils';
|
||||
|
||||
export default function thumbnails(options) {
|
||||
return (art) => ({
|
||||
...options,
|
||||
mounted: ($control) => {
|
||||
const {
|
||||
option,
|
||||
events: { loadImg },
|
||||
template: { $progress, $video },
|
||||
} = art;
|
||||
|
||||
let timer = null;
|
||||
let image = null;
|
||||
let loading = false;
|
||||
let isLoad = false;
|
||||
|
||||
function showThumbnails(posWidth) {
|
||||
const { url, number, column, width, height } = option.thumbnails;
|
||||
const width2 = width || image.naturalWidth / column;
|
||||
const height2 = height || width2 / ($video.videoWidth / $video.videoHeight);
|
||||
const perWidth = $progress.clientWidth / number;
|
||||
const perIndex = Math.floor(posWidth / perWidth);
|
||||
const yIndex = Math.ceil(perIndex / column) - 1;
|
||||
const xIndex = perIndex % column || column - 1;
|
||||
setStyle($control, 'backgroundImage', `url(${url})`);
|
||||
setStyle($control, 'height', `${height2}px`);
|
||||
setStyle($control, 'width', `${width2}px`);
|
||||
setStyle($control, 'backgroundPosition', `-${xIndex * width2}px -${yIndex * height2}px`);
|
||||
if (posWidth <= width2 / 2) {
|
||||
setStyle($control, 'left', 0);
|
||||
} else if (posWidth > $progress.clientWidth - width2 / 2) {
|
||||
setStyle($control, 'left', `${$progress.clientWidth - width2}px`);
|
||||
} else {
|
||||
setStyle($control, 'left', `${posWidth - width2 / 2}px`);
|
||||
}
|
||||
}
|
||||
|
||||
art.on('setBar', async (type, percentage, event) => {
|
||||
const isMobileDroging = type === 'played' && event && isMobile;
|
||||
|
||||
if (type === 'hover' || isMobileDroging) {
|
||||
if (!loading) {
|
||||
loading = true;
|
||||
image = await loadImg(option.thumbnails.url);
|
||||
isLoad = true;
|
||||
}
|
||||
|
||||
if (!isLoad) return;
|
||||
|
||||
const width = $progress.clientWidth * percentage;
|
||||
setStyle($control, 'display', 'flex');
|
||||
|
||||
if (width > 0 && width < $progress.clientWidth) {
|
||||
showThumbnails(width);
|
||||
} else {
|
||||
if (!isMobile) {
|
||||
setStyle($control, 'display', 'none');
|
||||
}
|
||||
}
|
||||
|
||||
if (isMobileDroging) {
|
||||
clearTimeout(timer);
|
||||
timer = setTimeout(() => {
|
||||
setStyle($control, 'display', 'none');
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
});
|
||||
mounted: () => {
|
||||
this.art.thumbnails = art.options.thumbnails;
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -30,6 +30,7 @@ import stateMix from './stateMix';
|
||||
import subtitleOffsetMix from './subtitleOffsetMix';
|
||||
import airplayMix from './airplayMix';
|
||||
import qualityMix from './qualityMix';
|
||||
import thumbnailsMix from './thumbnailsMix';
|
||||
import optionInit from './optionInit';
|
||||
import eventInit from './eventInit';
|
||||
|
||||
@@ -67,6 +68,7 @@ export default class Player {
|
||||
subtitleOffsetMix(art);
|
||||
airplayMix(art);
|
||||
qualityMix(art);
|
||||
thumbnailsMix(art);
|
||||
eventInit(art);
|
||||
optionInit(art);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
import { def, setStyle, isMobile } from '../utils';
|
||||
|
||||
export default function thumbnailsMix(art) {
|
||||
const {
|
||||
option,
|
||||
events: { loadImg },
|
||||
template: { $progress, $video },
|
||||
} = art;
|
||||
|
||||
let timer = null;
|
||||
let image = null;
|
||||
let loading = false;
|
||||
let isLoad = false;
|
||||
|
||||
function reset() {
|
||||
clearTimeout(timer);
|
||||
timer = null;
|
||||
image = null;
|
||||
loading = false;
|
||||
isLoad = false;
|
||||
}
|
||||
|
||||
function showThumbnails(posWidth) {
|
||||
const $thumbnails = art.controls?.thumbnails;
|
||||
if (!$thumbnails) return;
|
||||
|
||||
const { url, number, column, width, height } = option.thumbnails;
|
||||
const width2 = width || image.naturalWidth / column;
|
||||
const height2 = height || width2 / ($video.videoWidth / $video.videoHeight);
|
||||
const perWidth = $progress.clientWidth / number;
|
||||
const perIndex = Math.floor(posWidth / perWidth);
|
||||
const yIndex = Math.ceil(perIndex / column) - 1;
|
||||
const xIndex = perIndex % column || column - 1;
|
||||
setStyle($thumbnails, 'backgroundImage', `url(${url})`);
|
||||
setStyle($thumbnails, 'height', `${height2}px`);
|
||||
setStyle($thumbnails, 'width', `${width2}px`);
|
||||
setStyle($thumbnails, 'backgroundPosition', `-${xIndex * width2}px -${yIndex * height2}px`);
|
||||
if (posWidth <= width2 / 2) {
|
||||
setStyle($thumbnails, 'left', 0);
|
||||
} else if (posWidth > $progress.clientWidth - width2 / 2) {
|
||||
setStyle($thumbnails, 'left', `${$progress.clientWidth - width2}px`);
|
||||
} else {
|
||||
setStyle($thumbnails, 'left', `${posWidth - width2 / 2}px`);
|
||||
}
|
||||
}
|
||||
|
||||
art.on('setBar', async (type, percentage, event) => {
|
||||
const $thumbnails = art.controls?.thumbnails;
|
||||
if (!$thumbnails) return;
|
||||
|
||||
const isMobileDroging = type === 'played' && event && isMobile;
|
||||
|
||||
if (type === 'hover' || isMobileDroging) {
|
||||
if (!loading) {
|
||||
loading = true;
|
||||
image = await loadImg(option.thumbnails.url);
|
||||
isLoad = true;
|
||||
}
|
||||
|
||||
if (!isLoad) return;
|
||||
|
||||
const width = $progress.clientWidth * percentage;
|
||||
setStyle($thumbnails, 'display', 'flex');
|
||||
|
||||
if (width > 0 && width < $progress.clientWidth) {
|
||||
showThumbnails(width);
|
||||
} else {
|
||||
if (!isMobile) {
|
||||
setStyle($thumbnails, 'display', 'none');
|
||||
}
|
||||
}
|
||||
|
||||
if (isMobileDroging) {
|
||||
clearTimeout(timer);
|
||||
timer = setTimeout(() => {
|
||||
setStyle($thumbnails, 'display', 'none');
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
def(art, 'thumbnails', {
|
||||
get() {
|
||||
return art.option.thumbnails;
|
||||
},
|
||||
set(thumbnails) {
|
||||
if (thumbnails.url && !art.option.isLive) {
|
||||
art.option.thumbnails = thumbnails;
|
||||
reset();
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
Reference in new issue
Block a user