feat(component): 全屏组件

This commit is contained in:
sight
2022-02-17 23:51:25 +08:00
parent cf741e66c3
commit c10e1a2799
7 changed files with 476 additions and 2 deletions

View File

@@ -0,0 +1,9 @@
.layui-fullscreen {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 10;
overflow: auto;
}

View 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;

View 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>

View File

@@ -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,
};