feat(component): 全屏组件
This commit is contained in:
9
src/component/fullscreen/index.less
Normal file
9
src/component/fullscreen/index.less
Normal file
@@ -0,0 +1,9 @@
|
||||
.layui-fullscreen {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 10;
|
||||
overflow: auto;
|
||||
}
|
||||
8
src/component/fullscreen/index.ts
Normal file
8
src/component/fullscreen/index.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import type { App } from "vue";
|
||||
import Component from "./index.vue";
|
||||
|
||||
Component.install = (app: App) => {
|
||||
app.component(Component.name, Component);
|
||||
};
|
||||
|
||||
export default Component;
|
||||
214
src/component/fullscreen/index.vue
Normal file
214
src/component/fullscreen/index.vue
Normal file
@@ -0,0 +1,214 @@
|
||||
<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;
|
||||
// top?: string;
|
||||
// left?: string;
|
||||
// width?: string;
|
||||
// height?: 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(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 || "");
|
||||
// 实验内容
|
||||
// el.style.top = isRemove ? "" : (props.top || "");
|
||||
// el.style.left = isRemove ? "" : (props.left || "");
|
||||
// el.style.width = isRemove ? "" : (props.width || "");
|
||||
// el.style.height = isRemove ? "" : (props.height || "");
|
||||
}
|
||||
|
||||
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>
|
||||
@@ -76,6 +76,7 @@ import LaySplitPanel from "./component/splitPanel/index";
|
||||
import LaySplitPanelItem from "./component/splitPanelItem/index";
|
||||
import LayException from "./component/exception/index";
|
||||
import LayResult from "./component/result/index";
|
||||
import LayFullscreen from "./component/fullscreen/index";
|
||||
import LayConfigProvider from "./provider";
|
||||
|
||||
const components: Record<string, Component> = {
|
||||
@@ -149,6 +150,7 @@ const components: Record<string, Component> = {
|
||||
LaySubMenu,
|
||||
LayException,
|
||||
LayResult,
|
||||
LayFullscreen,
|
||||
LayConfigProvider,
|
||||
};
|
||||
|
||||
@@ -231,6 +233,7 @@ export {
|
||||
LaySubMenu,
|
||||
LayException,
|
||||
LayResult,
|
||||
LayFullscreen,
|
||||
LayConfigProvider,
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user