222 lines
5.2 KiB
Vue
222 lines
5.2 KiB
Vue
<script lang="ts">
|
|
export default {
|
|
name: "LayFullscreen",
|
|
};
|
|
</script>
|
|
|
|
<script lang="ts" setup>
|
|
import {
|
|
ref,
|
|
withDefaults,
|
|
computed,
|
|
onMounted,
|
|
onBeforeUnmount,
|
|
Ref,
|
|
} from "vue";
|
|
import "./index.less";
|
|
|
|
export interface LayFullscreenProps {
|
|
target?: HTMLElement;
|
|
immersive?: boolean;
|
|
position?: string;
|
|
zIndex?: string;
|
|
}
|
|
|
|
const props = withDefaults(defineProps<LayFullscreenProps>(), {
|
|
immersive: true,
|
|
});
|
|
|
|
const emit = defineEmits(["fullscreenchange"]);
|
|
type MethodMap = [
|
|
"requestFullscreen",
|
|
"exitFullscreen",
|
|
"fullscreenElement",
|
|
"fullscreenEnabled",
|
|
"fullscreenchange",
|
|
"fullscreenerror"
|
|
];
|
|
|
|
const methodMap: MethodMap[] = [
|
|
[
|
|
"requestFullscreen",
|
|
"exitFullscreen",
|
|
"fullscreenElement",
|
|
"fullscreenEnabled",
|
|
"fullscreenchange",
|
|
"fullscreenerror",
|
|
],
|
|
// New WebKit
|
|
[
|
|
"webkitRequestFullscreen",
|
|
"webkitExitFullscreen",
|
|
"webkitFullscreenElement",
|
|
"webkitFullscreenEnabled",
|
|
"webkitfullscreenchange",
|
|
"webkitfullscreenerror",
|
|
],
|
|
// Old WebKit
|
|
[
|
|
"webkitRequestFullScreen",
|
|
"webkitCancelFullScreen",
|
|
"webkitCurrentFullScreenElement",
|
|
"webkitCancelFullScreen",
|
|
"webkitfullscreenchange",
|
|
"webkitfullscreenerror",
|
|
],
|
|
[
|
|
"mozRequestFullScreen",
|
|
"mozCancelFullScreen",
|
|
"mozFullScreenElement",
|
|
"mozFullScreenEnabled",
|
|
"mozfullscreenchange",
|
|
"mozfullscreenerror",
|
|
],
|
|
[
|
|
"msRequestFullscreen",
|
|
"msExitFullscreen",
|
|
"msFullscreenElement",
|
|
"msFullscreenEnabled",
|
|
"MSFullscreenChange",
|
|
"MSFullscreenError",
|
|
],
|
|
];
|
|
// 默认请求全屏的元素
|
|
const defaultElement: HTMLElement = document.documentElement;
|
|
// 要请求全屏显示的元素
|
|
let targetEl: Ref<HTMLElement | undefined> = ref<HTMLElement | undefined>(
|
|
props.target || defaultElement
|
|
);
|
|
// 是否全屏
|
|
const isFullscreen = ref(false);
|
|
// 是否支持全屏
|
|
let isSupported: boolean = false;
|
|
|
|
// 包装全屏 API,屏蔽浏览器差异
|
|
const unprefixedMethods: MethodMap = methodMap[0];
|
|
const fullscreenAPI: Record<string, string> = {};
|
|
for (const methodList of methodMap) {
|
|
if (methodList[1] in document) {
|
|
for (const [index, method] of methodList.entries()) {
|
|
fullscreenAPI[unprefixedMethods[index]] = method;
|
|
}
|
|
isSupported = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 进入全屏
|
|
* @param targetEl 请求全屏显示的元素,不是所有元素都支持,建议用 div
|
|
*/
|
|
async function enter(targetEl: HTMLElement | undefined) {
|
|
if (!isSupported) return;
|
|
if (!targetEl) targetEl = activeEl.value || defaultElement;
|
|
let fullscreenEnter = null;
|
|
if (props.immersive) {
|
|
// @ts-ignore
|
|
fullscreenEnter = Promise.resolve(
|
|
// @ts-ignore
|
|
targetEl[fullscreenAPI.requestFullscreen]()
|
|
);
|
|
} else {
|
|
styleLayFullscreen(targetEl, false);
|
|
fullscreenEnter = Promise.resolve(
|
|
targetEl?.classList.add("layui-fullscreen")
|
|
);
|
|
}
|
|
return await fullscreenEnter?.then(() => {
|
|
isFullscreen.value = true;
|
|
emit("fullscreenchange", isFullscreen.value);
|
|
return !!document.fullscreenElement;
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 退出全屏
|
|
* @param targetEl 退出全屏元素
|
|
*/
|
|
async function exit(targetEl: HTMLElement | Document | undefined) {
|
|
if (!isSupported) return;
|
|
if (!targetEl) targetEl = activeEl.value || document;
|
|
let fullscreenExit = null;
|
|
if (props.immersive) {
|
|
// @ts-ignore
|
|
fullscreenExit = Promise.resolve(document[fullscreenAPI.exitFullscreen]());
|
|
} else {
|
|
if (targetEl instanceof Document) return;
|
|
styleLayFullscreen(targetEl, true);
|
|
fullscreenExit = Promise.resolve(
|
|
targetEl?.classList.remove("layui-fullscreen")
|
|
);
|
|
}
|
|
return await fullscreenExit?.then(() => {
|
|
isFullscreen.value = false;
|
|
emit("fullscreenchange", isFullscreen.value);
|
|
return !!document.fullscreenElement;
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 进入或退出全屏
|
|
*/
|
|
async function toggle() {
|
|
if (isFullscreen.value) {
|
|
await exit(activeEl.value);
|
|
} else {
|
|
await enter(activeEl.value);
|
|
}
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param el HTML 元素
|
|
* @param isRemove 是否移除样式
|
|
*/
|
|
const styleLayFullscreen = function (
|
|
el: HTMLElement,
|
|
isRemove: boolean = false
|
|
) {
|
|
el.style.position = isRemove ? "" : props.position || "";
|
|
el.style.zIndex = isRemove ? "" : props.zIndex || "";
|
|
};
|
|
|
|
const activeEl = computed(() => (targetEl.value = props.target));
|
|
|
|
/**
|
|
* 处理 fullscreenchange 和浏览器窗口内全屏 Escape 按键事件
|
|
* @param event Escape 键盘事件
|
|
*/
|
|
const onFullscreenchange = function (event: KeyboardEvent) {
|
|
if (isFullscreen.value && !document.fullscreenElement) {
|
|
if (props.immersive) {
|
|
isFullscreen.value = false;
|
|
emit("fullscreenchange", isFullscreen.value);
|
|
} else if (event.key === "Escape") {
|
|
exit(activeEl.value);
|
|
}
|
|
}
|
|
};
|
|
|
|
onMounted(() => {
|
|
//@ts-ignore
|
|
document.addEventListener(fullscreenAPI.fullscreenchange, onFullscreenchange);
|
|
document.addEventListener("keydown", onFullscreenchange);
|
|
});
|
|
|
|
onBeforeUnmount(() => {
|
|
//@ts-ignore
|
|
document.addEventListener(fullscreenAPI.fullscreenchange, onFullscreenchange);
|
|
document.addEventListener("keydown", onFullscreenchange);
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<slot
|
|
name="default"
|
|
:isFullscreen="isFullscreen"
|
|
:enter="enter"
|
|
:exit="exit"
|
|
:toggle="toggle"
|
|
></slot>
|
|
</template>
|