问题描述
我在使用选项卡可见性时收到此错误。其中“文档”类型不存在“msHidden”和“webkitHidden”
const TabVisibilityComponent = () => {
let hidden = null;
let visibilityChange = '';
const [action,setAction] = useState('show');
if (typeof document.hidden !== 'undefined') {
hidden = 'hidden';
visibilityChange = 'visibilitychange';
} else if (typeof document.msHidden !== 'undefined') {
hidden = 'msHidden';
visibilityChange = 'msvisibilitychange';
} else if (typeof document.webkitHidden !== 'undefined') {
hidden = 'webkitHidden';
visibilityChange = 'webkitvisibilitychange';
}
const handleVisibilityChange = () => {
if (document.hidden) {
setAction('hide');
} else {
setAction('show');
}
};
useEffect(() => {
document.addEventListener('visibilitychange',handleVisibilityChange,false);
window.addEventListener(
'focus',function() {
setAction('show');
},false,);
window.addEventListener('blur',function() {
setAction('hide');
},false);
},[visibilityChange]);
return <p></p>;
};
export default TabVisibilityComponent;
我尝试在 'lib.dom.d.ts' 文件的 Document 界面中添加 'readonly msHidden: boolean',因为 hidden 工作正常,它是在该文件中声明为只读布尔值,因此对 msHidden 和 webkitHidden 尝试了相同的方法,但它不起作用。我已经看到很多人使用这个代码,但不知道我的错误是什么。如果有人对此有解决方案,我会很高兴!
解决方法
代码直接来自 MDN docs,所以代码本身是正确的。问题是:
-
lib.dom
定义确实包含浏览器特定的属性。
解决此问题的一种方法是将文档作为参数传递给函数,该函数将这些属性定义为可选。
const hiddenPropName = (document: Document & {msHidden?: boolean; webkitHidden?: boolean}) => {
if (typeof document.hidden !== "undefined" ) {
return "hidden";
} else if (typeof document.msHidden !== "undefined") {
return "msHidden";
} else if (typeof document.webkitHidden !== "undefined") {
return "webkitHidden";
}
// not sure how to handle when none exist
}
但就 Typescript 而言,document.hidden
始终存在。
看起来 caniuse 上的带前缀和不带前缀的支持数字几乎没有任何区别。所以你可以放弃 msHidden
和 webkitHidden
。
- 您忽略了您设置的
hidden
和visibilityChange
变量。
示例中代码的第一部分只是将变量 hidden
和 visibilityChange
设置为属性的名称,以便它们稍后可以访问正确的属性。该示例使用 document[hidden]
,其中 hidden
是一个变量,但您使用了 document.hidden
,它始终获取属性“hidden”,而不是“msHidden”或“webkitHidden”。
他们还为 document.addEventListener
中的事件使用了一个变量。
如果你想支持前缀,那么你需要使用变量属性和事件名称。如果没有,只需删除整个第一个代码块。
- 您没有根据 React 正确调整代码。
您希望确保您的 useEffect
挂钩具有正确的依赖项,并且理想情况下您应该在您的 useEffect
中使用清理函数来移除卸载时的事件侦听器。
这里最困难的部分是确保您不会创建任何在评估时使用过时的 document
值的陈旧闭包。我实际上不确定不玩它是否正确:
const TabVisibilityComponent = () => {
const [action,setAction] = useState("show");
useEffect(() => {
const hide = () => setAction("hide");
const show = () => setAction("show");
const handleVisibilityChange = () => {
document.hidden ? hide() : show();
};
document.addEventListener(
"visibilitychange",handleVisibilityChange,false
);
window.addEventListener("focus",show,false);
window.addEventListener("blur",hide,false);
return () => {
document.removeEventListener("visibilitychange",handleVisibilityChange);
window.removeEventListener("focus",show);
window.removeEventListener("blur",hide);
};
},[setAction]);
return <p></p>;
};