import {useLayoutEffect,useRef,useEffect}from 'react'
import {BasicTarget,getTargetElement}from './utils/dom'
import useBoolean from './useBoolean'
// 他们都用了一个库 screenfull
export interface Options{
onExitFull?:()=>void,
onFull?:()=>void
}
// 暴露的接口
interface Callback{
setFull:()=>void,
exitFull:()=>void,
toggleFull:()=>void
}
type Value=boolean
// let Value:boolean
// 这样就不能做下面的操作了
type Result=[Value,Callback]
// interface好像也不能表示这种数组的返回数据类型
export default function useFullScreen(
target?:BasicTarget,
options?:Options
):Result{
const {onExitFull,onFull}=options||{}
const [state,{toggle,setTrue,setFalse}]=useBoolean(false)
useLayoutEffect(()=>{
if(!document.fullscreenEnabled)return
// if(!state){return}
// 首次是非全屏就不操作,现在的操作就是第一次切换为true状态之后都不会在执行下面的操作了
const el=getTargetElement(target)
function handleChange(){
let isFull=document.fullscreen
// || document.mozIsFullScreen || document.webkitIsFullScreen
// console.log(isFull,'isFull')
// 这里执行很多次的问题还是找不到....
if(isFull){
setTrue()
}else{
setFalse()
}
// 总的来说,你是不能再这里取旧的state,不然就会爆炸,反正就是这个状态不太对应该要引入一个额外的,全局变量,整体知道现在到底是全屏还是非全屏
}
if(state){
try{
if(el==undefined){
document.documentElement.requestFullscreen()
}else{
let target=el as Element
target.requestFullscreen()
}
// 注意,这是一个promise的操作。要写容错
document.addEventListener('fullscreenchange',handleChange)
}catch(error){
if(onExitFull){
onExitFull()
}
}
}else{
if(document.fullscreenElement){
document.exitFullscreen()
}
if(onExitFull){
onExitFull()
}
}
// 这个console打印是对的
// 通过别的地方进行的全屏切换,需要和state同步状态,
// 如果添加在这里,虽然最后是对的,但是每次都是会把之前的全部状态转换都会console一遍,不知道是不是开发版本的问题
document.addEventListener('fullscreenchange',()=>{
// console.log("全屏切换",state)
// 这里拿到的还是旧的
// if(state){
// setFalse()
// }else{
// setTrue()
// }
// 而且感觉是循环引用导致卡死:API只能由用户手势启动,会有这个报错
})
return()=>{
// document.removeEventListener('fullscreenchange',()=>{
// console.log("全屏切换卸载")
// })
}
},[state,typeof target==='function'?undefined:target])
useEffect(()=>{
document.addEventListener('fullscreenerror',()=>{
console.log('全屏切换错误')
})
// 主要就是
document.addEventListener('fullscreenchange',()=>{
console.log("全屏切换")
// 通过别的地方进行的全屏切换,需要和state同步状态,主要是esc返回,还有视频一般会自带一个取消全屏的按钮,如果在外面加的话还是有点繁琐
// 如果添加在这里,虽然最后是对的,但是每次都是会把之前的全部状态转换都会console一遍,不知道是不是开发版本的问题
})
return ()=>{
document.removeEventListener('fullscreenchange',()=>{
console.log("全屏切换卸载")
})
document.removeEventListener('fullscreenerror',()=>{
console.log('全屏切换卸载')
})
}
},[])
const toggleFull = () => toggle()
// 他是做在了这里,重写了函数,改为一个不会传参数的了...
// 感觉就是想偷一点点懒都不行
return [!!state,{
setFull: setTrue,
exitFull: setFalse,
toggleFull,
}]
}
// 1.文档全屏
const [isFullscreen,{setFull,exitFull,toggleFull}]=useFullScreen()
// 指定元素全屏,一般是video元素
const videoRef=useRef()as React.MutableRefObject<HTMLVideoElement>
// const [isFullscreen,{setFull,exitFull,toggleFull}]=useFullScreen(videoRef)
// 这个也是可以的
return (
<div>
<video src="" ref={videoRef}></video>
<img src="" alt=""/>
<button onClick={setFull}>full</button>
<button onClick={exitFull}>exit</button>
<button onClick={toggleFull}>toggle</button>
{/* 为什么会把event给传进去 */}
</div>
)
网友评论