0
点赞
收藏
分享

微信扫一扫

js 基于能力检测进行浏览器分析

虽然可能有人觉得能力检测类似于黑科技,但恰当地使用能力检测可以精准地分析运行代码的浏览器。使用能力检测而非用户代理检测的优点在于,伪造用户代理字符串很简单,而伪造能够欺骗能力检测的浏览器特性却很难。 检测特性 可以按照能力将浏览器归类。如果你的应用程序需要使用特定的浏览器能力,那么最好集中检测所有能力,而不是等到用的时候再重复检测。比如:

let hasNSPlugins = !!(navigator.plugins && navigator.plugins.length); 
// 检测浏览器是否具有 DOM Level 1 能力
let hasDOM1 = !!(document.getElementById && document.createElement && 
 document.getElementsByTagName);

这个例子完成了两项检测:一项是确定浏览器是否支持 Netscape 式的插件,另一项是检测浏览器是否具有 DOM Level 1 能力。保存在变量中的布尔值可以用在后面的条件语句中,这样比重复检测省事多了。 检测浏览器 可以根据对浏览器特性的检测并与已知特性对比,确认用户使用的是什么浏览器。这样可以获得比用户代码嗅探(稍后讨论)更准确的结果。但未来的浏览器版本可能不适用于这套方案。下面来看一个例子,根据不同浏览器独有的行为推断出浏览器的身份。这里故意没有使用 navigator. userAgent 属性,后面会讨论它:

constructor() { 
 // 测试条件编译
 // IE6~10 支持
 this.isIE_Gte6Lte10 = /*@cc_on!@*/false; 
 // 测试 documentMode 
 // IE7~11 支持
 this.isIE_Gte7Lte11 = !!document.documentMode;
 // 测试 StyleMedia 构造函数
 // Edge 20 及以上版本支持
 this.isEdge_Gte20 = !!window.StyleMedia; 
 // 测试 Firefox 专有扩展安装 API 
 // 所有版本的 Firefox 都支持
 this.isFirefox_Gte1 = typeof InstallTrigger !== 'undefined'; 
 // 测试 chrome 对象及其 webstore 属性
 // Opera 的某些版本有 window.chrome,但没有 window.chrome.webstore 
 // 所有版本的 Chrome 都支持
 this.isChrome_Gte1 = !!window.chrome && !!window.chrome.webstore; 
 // Safari 早期版本会给构造函数的标签符追加"Constructor"字样,如:
 // window.Element.toString(); // [object ElementConstructor] 
 // Safari 3~9.1 支持
 this.isSafari_Gte3Lte9_1 = /constructor/i.test(window.Element); 
 // 推送通知 API 暴露在 window 对象上
 // 使用默认参数值以避免对 undefined 调用 toString() 
 // Safari 7.1 及以上版本支持
 this.isSafari_Gte7_1 = 
 (({pushNotification = {}} = {}) => 
 pushNotification.toString() == '[object SafariRemoteNotification]' 
 )(window.safari); 
 // 测试 addons 属性
 // Opera 20 及以上版本支持
 this.isOpera_Gte20 = !!window.opr && !!window.opr.addons; 
 } 
 isIE() { return this.isIE_Gte6Lte10 || this.isIE_Gte7Lte11; } 
 isEdge() { return this.isEdge_Gte20 && !this.isIE(); } 
 isFirefox() { return this.isFirefox_Gte1; } 
 isChrome() { return this.isChrome_Gte1; } 
 isSafari() { return this.isSafari_Gte3Lte9_1 || this.isSafari_Gte7_1; } 
 isOpera() { return this.isOpera_Gte20; } 
}

这个类暴露的通用浏览器检测方法使用了检测浏览器范围的能力测试。随着浏览器的变迁及发展,可以不断调整底层检测逻辑,但主要的 API 可以保持不变。 能力检测的局限 通过检测一种或一组能力,并不总能确定使用的是哪种浏览器。以下“浏览器检测”代码(或其他类似代码)经常出现在很多网站中,但都没有正确使用能力检测:

let isFirefox = !!(navigator.vendor && navigator.vendorSub); 
// 不要这样做!假设太多
let isIE = !!(document.all && document.uniqueID);

这是错误使用能力检测的典型示例。过去,Firefox 可以通过 navigator.vendor 和 navigator. vendorSub 来检测,但后来 Safari 也实现了同样的属性,于是这段代码就会产生误报。为确定 IE,这段代码检测了 document.all 和 document.uniqueID。这是假设 IE 将来的版本中还会继续存在这两个属性,而且其他浏览器也不会实现它们。不过这两个检测都使用双重否定操作符来产生布尔值(这样可以生成便于存储和访问的结果)。

举报

相关推荐

0 条评论