头图

运行环境:
EDGE浏览器120.0.2210.144 (正式版本) (64 位);
谷歌版本 121.0.6167.85(正式版本)(64 位);
dependencies: {

"vue": "^3.3.4"

},
"devDependencies": {

"@types/node": "^20.11.4",
"@vitejs/plugin-vue": "^4.2.3",
"typescript": "^5.0.2",
"vite": "^4.4.5",
"vite-plugin-require-transform": "^1.0.21",
"vue-tsc": "^1.8.5"

}

问题:
作者本来想做一个需求,就是按F11浏览器全屏,隐藏一个东西;再按一下显示出来,结果事与愿违,下面敲重点!
下面讲通过EDGE浏览器和chrome浏览器按F11全屏的形式
1)onresize(网上的方法来监听全屏切换)执行两次,F11切回非全屏执行一次。
2)keydown事件再按F11退出无法触发对应keydown事件(按F11全屏可以监听到)。更恶心的是获取当前浏览器全屏状态(isFullScreen方法)一直都是false状态(非全屏)(ˉ▽ˉ;)...

onMounted(()=>{
    //注册监听
    console.log("mounted")
    window.addEventListener("keydown", keydown, true)// 监听按键事件
    
})
onBeforeUnmount(()=>{
    console.log("unmount")
    window.removeEventListener("keydown", keydown, true)// 移除监听按键事件
})

window.onresize = function (){
        console.log("resize")
        if(isFullScreen()){
             alert("全屏")
         }else{
            alert("非全屏")
        }

  }

function isFullScreen() {
  return (
    (document.fullscreenElement && document.fullscreenElement !== null) ||
    (document.webkitFullscreenElement && document.webkitFullscreenElement !== null) ||
    (document.mozFullScreenElement && document.mozFullScreenElement !== null) ||
    (document.msFullscreenElement && document.msFullscreenElement !== null)
  );
//如果没封装,document.webkitFullscreenElement等其它浏览器内核会变红。
}

特别说一下 ts不支持webkitFullscreenElement,mozFullScreenElement等属性,因此在编写过程中会有报错。
解决方法:在自己的.d.ts文件中可以对ts系统自带的interface进行声明合并(扩展);(作者放在vite-env.d.ts文件中)

/// <reference types="vite/client" />

// 注册其他浏览器内核方法
interface HTMLElement {
    // 进入全屏
    webkitRequestFullscreen(options?: FullscreenOptions): Promise<void>;
    webkitRequestFullScreen(options?: FullscreenOptions): Promise<void>;
    msRequestFullscreen(options?: FullscreenOptions): Promise<void>;
    mozRequestFullScreen(options?: FullscreenOptions): Promise<void>;

    // 监听全屏
    onwebkitfullscreenchange: ((this: Element, ev: Event) => any) | null;
    onmozfullscreenchange: ((this: Element, ev: Event) => any) | null;
    MSFullscreenChange: ((this: Element, ev: Event) => any) | null;
}

interface Document {
    // 当前全屏的元素
    readonly webkitFullscreenElement: Element | null;
    readonly msFullscreenElement: Element | null;
    readonly mozFullScreenElement: Element | null;

    // 退出全屏
    webkitExitFullscreen(): Promise<void>;
    msExitFullscreen(): Promise<void>;
    mozCancelFullScreen(): Promise<void>;
}

解决方案:
改用按钮点击的形式进行浏览器全屏状态切换。

useFullScreen.ts:

type RFSMethodName = 'webkitRequestFullScreen' | 'requestFullscreen' | 'msRequestFullscreen' | 'mozRequestFullScreen';
type EFSMethodName = 'webkitExitFullscreen' | 'msExitFullscreen' | 'mozCancelFullScreen' | 'exitFullscreen';
type FSEPropName = 'webkitFullscreenElement' | 'msFullscreenElement' | 'mozFullScreenElement' | 'fullscreenElement';
type ONFSCPropName = 'onfullscreenchange' | 'onwebkitfullscreenchange' | 'onmozfullscreenchange' | 'MSFullscreenChange';

/**
 * caniuse
 * https://caniuse.com/#search=Fullscreen
 * 参考 MDN, 并不确定是否有o前缀的, 暂时不加入
 * https://developer.mozilla.org/zh-CN/docs/Web/API/Element/requestFullscreen
 * 各个浏览器
 * https://www.wikimoe.com/?post=82
 */
const DOC_EL = document.documentElement;

let RFC_METHOD_NAME: RFSMethodName = 'requestFullscreen';
let EFS_METHOD_NAME: EFSMethodName = 'exitFullscreen';
let FSE_PROP_NAME: FSEPropName = 'fullscreenElement';
let ON_FSC_PROP_NAME: ONFSCPropName = 'onfullscreenchange';

if (`webkitRequestFullScreen` in DOC_EL) {
    RFC_METHOD_NAME = 'webkitRequestFullScreen';
    EFS_METHOD_NAME = 'webkitExitFullscreen';
    FSE_PROP_NAME = 'webkitFullscreenElement';
    ON_FSC_PROP_NAME = 'onwebkitfullscreenchange';
} else if (`msRequestFullscreen` in DOC_EL) {
    RFC_METHOD_NAME = 'msRequestFullscreen';
    EFS_METHOD_NAME = 'msExitFullscreen';
    FSE_PROP_NAME = 'msFullscreenElement';
    ON_FSC_PROP_NAME = 'MSFullscreenChange';
} else if (`mozRequestFullScreen` in DOC_EL) {
    RFC_METHOD_NAME = 'mozRequestFullScreen';
    EFS_METHOD_NAME = 'mozCancelFullScreen';
    FSE_PROP_NAME = 'mozFullScreenElement';
    ON_FSC_PROP_NAME = 'onmozfullscreenchange';
} else if (!(`requestFullscreen` in DOC_EL)) {
    throw `当前浏览器不支持Fullscreen API !`;
}

/**
 * 启用全屏
 * @param  {HTMLElement} 元素
 * @param  {FullscreenOptions} 选项
 * @returns {Promise}
 */
export function beFull(el: HTMLElement = DOC_EL, options?: FullscreenOptions): Promise<void> {
    return el[RFC_METHOD_NAME](options);
}

/**
 * 退出全屏
 */
export function exitFull(): Promise<void> {
    return document[EFS_METHOD_NAME]();
}

/**
 * 元素是否全屏
 * @param {HTMLElement}
 */
export function isFull(el: HTMLElement | EventTarget): boolean {
    return el === document[FSE_PROP_NAME]
}

/**
 * 切换全屏/关闭
 * @param  {HTMLElement} 目标元素
 * @returns {Promise}
 */
export function toggleFull(el: HTMLElement = DOC_EL, options?: FullscreenOptions): Promise<void> {
    if (isFull(el)) {
        return exitFull();
    } else {
        return beFull(el, options)
    }
}

/**
 * 当全屏/退出时触发
 * @param  {HTMLElement} 元素
 * @param  {(isFull: boolean) => void} 返回"是否全屏"
 */
export function watchFull(el: HTMLElement= DOC_EL, callback: (isFull: boolean) => void) {
    const cancel = () => {
        el.onfullscreenchange = null;
    };

    const handler = (event: Event) => {
        if (null !== event.target) {
            callback(isFull(event.target));
        }
    }

    // 这里addEventListener不好使
    el[ON_FSC_PROP_NAME] = handler;

    return {
        cancel
    }
}

SPA组件应用代码:

<template>
<div class="y_rot" v-if="isLoaded">
    isNotFullscreen:{{ isNotFullscreen }}
    <select id="animate-list" v-model="selectedAnimate" v-show="isNotFullscreen">
      <option value="" disabled selected hidden></option> <!-- 默认空白选项 -->
      <option v-for="(item, index) in arrangeList" :key="index" :value="item.id">{{ item.name }}</option>
    </select>
<button @click="toggle($event)">全屏切换</button>
</div>
</template>
<script setup lang="ts">
 import { onBeforeUnmount,onMounted, reactive,ref } from 'vue';
 import  * as useFullscreen from './hooks/useFullscreen.ts';
 let isNotFullscreen = ref(true);
 let imgList= reactive(UserConfig);
 let selectedAnimate = ref("");
 let arrangeList = reactive([
        { name: '苹果', id: 'apple' },
        { name: '香蕉', id: 'banana' },
        { name: '芒果', id: 'mogo'}
   ]);
onMounted(()=>{
    isLoaded.value = true;
    // 获取需要全屏的元素
    //注册监听
    console.log("mounted")
    window.addEventListener("keydown", keydown, true)// 监听按键事件
    

})
onBeforeUnmount(()=>{
    console.log("unmount")
    window.removeEventListener("keydown", keydown, true)// 移除监听按键事件
})
async function toggle(event:any){
    await useFullscreen.toggleFull(document.documentElement as HTMLElement);
    
}
useFullscreen.watchFull(document.documentElement as HTMLElement,(isFull)=>{
            console.log(isFull)
            isNotFullscreen.value = !isFull;
            //alert(isFullScreen());
        })
async function keydown(event:any){
    console.log(event.keyCode)
    if (event.keyCode === 122) {
        console.log("f11")
      }
}
</script>

参考文献:主流判断当前是否全屏链接地址
TS-全屏hook封装参考链接地址


阳哥
14 声望0 粉丝

一个code爱好者,一个户外运动的爱好者,一个喜欢音乐的爱好者。