关键要点
- JavaScript 的特性检测(测试程序员想要使用的特性)并不总是可靠的。例如,在 Internet Explorer 中测试 ActiveXObject 以进行 Ajax 请求、映射到 DOM 属性的 HTML 属性以及对用户行为的假设(例如检测触摸设备)等。
- 当特性检测失败时,有时需要采用浏览器检测。但是,建议使用专有对象测试而不是 navigator 信息,并将其用于排除浏览器而不是包含浏览器。
- 在实现浏览器检测时,务必极其小心。始终首先假设完全符合特性测试,只有在知道某个特性无法按预期工作时才求助于浏览器检测。此外,用于对象和特性测试的语法会影响检测的成功率,因此选择正确的语法至关重要。
曾经,浏览器检测是 JavaScript 程序员的看家本领。如果我们知道某些功能在 IE5 中有效但在 Netscape 4 中无效,我们会测试该浏览器并相应地修改代码。例如:
if (navigator.userAgent.indexOf('MSIE 5') != -1) { // 我们认为此浏览器是 IE5 }
但是,当我第一次加入这个行业时,军备竞赛就已经开始了!供应商正在向用户代理字符串添加额外的值,因此它们看起来像是其竞争对手的浏览器,也是它们自己的浏览器。例如,这是 Mac 版 Safari 5:
<code>Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/534.59.10 (KHTML, like Gecko) Version/5.1.9 Safari/534.59.10</code>
这将匹配对“Safari”、“Webkit”以及“KHTML”(Webkit 基于的 Konqueror 代码库)的测试;但它也匹配“Gecko”(这是 Firefox 的渲染引擎),当然还有“Mozilla”(由于历史原因,几乎每个浏览器都声称自己是 Mozilla)。
添加所有这些值的目的是规避浏览器检测。如果脚本假设只有 Firefox 才能处理特定功能,否则可能会排除 Safari,即使它可能也能工作。别忘了用户自己可以更改他们的用户代理——我曾经将我的浏览器设置为识别为“Googlebot/1.0”,这样我就可以访问网站所有者认为仅供抓取的内容!
因此,随着时间的推移,这种浏览器检测已成为一个不可能解开的乱麻,并且在很大程度上已不再使用,取而代之的是更好的东西——特性检测。
特性检测只是测试我们想要使用的特性。例如,如果我们需要 getBoundingClientRect
(获取元素相对于视口的位 置),那么重要的是浏览器是否支持它,而不是它是哪个浏览器;因此,与其测试受支持的浏览器,不如测试特性本身:
if (typeof document.documentElement.getBoundingClientRect != "undefined") { // 浏览器支持此函数 }
不支持该函数的浏览器将返回“undefined”类型,因此不会通过条件。无需在任何特定浏览器中测试脚本,我们就知道它要么正确工作,要么静默失败。
或者我们……?
但事实是——特性检测也不是完全可靠的——有时它会失败。因此,让我们现在看看一些示例,看看我们可以做些什么来解决每个案例。
ActiveX 对象
也许特性检测失败最著名的例子是测试 ActiveXObject 以在 Internet Explorer 中进行 Ajax 请求。
ActiveX 是后期绑定对象的示例,其实际意义是您无法知道它是否受支持直到您尝试使用它。因此,如果用户禁用了 ActiveX,则以下代码将引发错误:
if (navigator.userAgent.indexOf('MSIE 5') != -1) { // 我们认为此浏览器是 IE5 }
要解决此问题,我们需要使用异常处理——尝试实例化对象,捕获任何失败,并相应地处理它:
<code>Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/534.59.10 (KHTML, like Gecko) Version/5.1.9 Safari/534.59.10</code>
映射到 DOM 属性的 HTML 属性
属性映射通常用于测试与 HTML5 属性一起使用的 API 的支持。例如,通过查找可拖动属性来检查具有 [draggable="true"]
的元素是否支持拖放 API:
if (typeof document.documentElement.getBoundingClientRect != "undefined") { // 浏览器支持此函数 }
这里的问题是 IE8 或更早版本会自动将所有HTML 属性映射到 DOM 属性。这就是为什么 getAttribute
在这些旧版本中如此混乱的原因,因为它根本不返回属性,而是返回 DOM 属性。
这意味着如果我们使用已经具有属性的元素:
if (typeof window.ActiveXObject != "undefined") { var request = new ActiveXObject("Microsoft.XMLHTTP"); }
那么即使它们不支持,IE8 或更早版本也会返回 true
用于 ("draggable" in element)
。
属性可以是任何内容:
if (typeof window.ActiveXObject != "undefined") { try { var request = new ActiveXObject("Microsoft.XMLHTTP"); } catch (ex) { request = null; } if (request !== null) { //... 我们有一个请求对象 } }
但结果将相同——IE8 或更早版本将返回 true
用于 ("nonsense" in element)
。
在这种情况下,解决方案是使用不具有该属性的元素进行测试,最安全的方法是使用创建的元素:
if ("draggable" in element) { // 浏览器支持拖放 }
对用户行为的假设
您可能已经看到使用以下代码来检测触摸设备:
<div draggable="true"> ... </div>
大多数触摸设备在触发点击事件之前会实现人工延迟(通常约为 300 毫秒),这是为了避免在双击元素的同时也点击它们。但这会使应用程序感觉迟缓且无响应,因此开发人员有时会使用该特性测试来分叉事件:
<div nonsense="true"> ... </div>
但是,此条件源于一个错误的假设——因为设备支持触摸,因此将使用触摸。但是触摸屏笔记本电脑呢?用户可能正在触摸屏幕,也可能正在使用鼠标或触控板;上面的代码无法处理这种情况,因此用鼠标单击将不会执行任何操作。
在这种情况下,解决方案根本不是测试事件支持——而是同时绑定两个事件,然后使用 preventDefault
来阻止触摸生成点击:
if (navigator.userAgent.indexOf('MSIE 5') != -1) { // 我们认为此浏览器是 IE5 }
完全不起作用的东西
承认这一点很痛苦,但有时我们不需要测试的不是特性——而是浏览器——因为特定浏览器声称支持某些不起作用的东西。最近的一个例子是 Opera 12 中的 setDragImage()
(这是拖放 dataTransfer
对象的一种方法)。
特性测试在这里失败是因为 Opera 12 声称支持它;异常处理也无济于事,因为它不会引发任何错误。它只是不起作用:
<code>Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/534.59.10 (KHTML, like Gecko) Version/5.1.9 Safari/534.59.10</code>
现在,如果您只想尝试添加自定义拖动图像,并且乐于在不支持的情况下保留默认值(这将发生),那么这可能很好。但是,如果您的应用程序确实需要自定义图像,以至于不支持它的浏览器应该使用完全不同的实现(即使用自定义 JavaScript 来实现所有拖动行为)呢?
或者,如果浏览器实现了某些功能,但存在无法避免的渲染错误呢?有时我们别无选择,只能明确检测有问题的浏览器,并将其排除在使用它本来会尝试支持的功能之外。
因此,问题变成了——实现浏览器检测最安全的方法是什么?
我有两点建议:
- 优先使用专有对象测试而不是 navigator 信息。
- 将其用于排除浏览器而不是包含浏览器。
例如,可以使用 window.opera
对象检测 Opera 12 或更早版本,因此我们可以使用该排除来测试可拖动支持:
if (typeof document.documentElement.getBoundingClientRect != "undefined") { // 浏览器支持此函数 }
最好使用专有对象而不是标准对象,因为当发布新浏览器时,测试结果不太可能发生变化。以下是一些我最喜欢的示例:
if (typeof window.ActiveXObject != "undefined") { var request = new ActiveXObject("Microsoft.XMLHTTP"); }
对象测试也可以与特性测试结合使用,以确定特定浏览器中特定特性的支持,或者在紧急情况下,定义更精确的浏览器条件:
if (typeof window.ActiveXObject != "undefined") { try { var request = new ActiveXObject("Microsoft.XMLHTTP"); } catch (ex) { request = null; } if (request !== null) { //... 我们有一个请求对象 } }
我们已经注意到用户代理字符串是一个不可靠的混乱,但供应商字符串实际上相当可预测,并且可以用来可靠地测试 Chrome 或 Safari:
if ("draggable" in element) { // 浏览器支持拖放 }
所有这一切的黄金法则是要极其小心。确保您在尽可能多的浏览器中测试条件,并仔细考虑它们的向前兼容性——目标是使用浏览器条件来排除浏览器,因为存在已知的错误,而不是因为已知的特性而包含它们(这就是特性测试的目的)
从根本上说,始终首先假设完全符合特性测试——除非您知道情况并非如此,否则假设特性将按预期工作。
选择测试语法
在结束之前,我想检查一下我们可以用于对象和特性测试的不同类型的语法。例如,近年来,以下语法已变得很常见:
if (navigator.userAgent.indexOf('MSIE 5') != -1) { // 我们认为此浏览器是 IE5 }
过去我们无法使用它,因为 IE5 及其同类产品会因语法而引发错误;但现在我们不必支持这些浏览器,这已不再是问题。
从本质上讲,它与以下内容完全相同,但编写起来更短:
<code>Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/534.59.10 (KHTML, like Gecko) Version/5.1.9 Safari/534.59.10</code>
但是,测试条件通常依赖于自动类型转换:
if (typeof document.documentElement.getBoundingClientRect != "undefined") { // 浏览器支持此函数 }
我们在某些浏览器对象测试(例如 window.opera
测试)中早些时候使用了该语法,这是安全的,因为对象如何评估——任何已定义的对象或函数都将始终评估为 true,而如果它未定义,则将评估为 false。
但是我们可能正在测试有效返回 null 或空字符串的东西,这两者都评估为 false。例如,style.maxWidth
属性有时用于排除 IE6:
if (typeof window.ActiveXObject != "undefined") { var request = new ActiveXObject("Microsoft.XMLHTTP"); }
只有在支持 maxWidth
属性并且具有作者定义的值时,它才会评估为 true,因此如果我们这样编写测试,它可能会失败:
if (typeof window.ActiveXObject != "undefined") { try { var request = new ActiveXObject("Microsoft.XMLHTTP"); } catch (ex) { request = null; } if (request !== null) { //... 我们有一个请求对象 } }
一般规则是这样的:依赖于自动类型转换对于对象和函数是安全的,但对于字符串和数字或可能为 null 的值并不一定安全。
话虽如此——如果您能安全地使用它,那就这样做,因为它在现代浏览器中通常要快得多(可能是因为它们针对这种类型的条件进行了优化)。
有关此内容的更多信息,请参阅:现实世界中的自动类型转换。
关于 JavaScript 特性检测的常见问题
什么是 JavaScript 特性检测,为什么它很重要?
JavaScript 特性检测是开发人员用来确定用户浏览器是否支持特定特性或 API 的一种技术。这至关重要,因为并非所有浏览器都支持 JavaScript 的所有特性。通过使用特性检测,开发人员可以为不受支持的特性提供替代解决方案或后备方案,确保网站或应用程序在不同浏览器上都能正确运行。这增强了用户体验并确保了兼容性。
JavaScript 特性检测是如何失败的?
JavaScript 特性检测可能会由于多种原因而失败。一个常见的原因是特性检测代码的实现不正确。例如,如果代码检查对象中不存在的属性,它将返回 undefined,导致假阴性。另一个原因可能是浏览器的怪癖或错误,这可能会导致特性检测给出不准确的结果。
特性检测和浏览器检测有什么区别?
特性检测涉及检查用户浏览器是否支持特定特性或 API,而浏览器检测则识别用户的浏览器和版本。虽然这两种技术都旨在确保兼容性和功能性,但特性检测通常被认为是一种更好的实践,因为它直接检查特性,而不是根据浏览器类型或版本来假设其支持。
如何使用 JavaScript 检测移动设备?
您可以使用 JavaScript 中的 navigator.userAgent
属性来检测移动设备。此属性返回一个字符串,表示浏览器的用户代理标头。通过检查此字符串中的特定关键字(例如“Android”、“iPhone”或“iPad”),您可以确定用户是否在移动设备上。
什么是 Feature.js,它如何帮助进行特性检测?
Feature.js 是一个轻量级、快速且简单的 JavaScript 实用程序,用于特性检测。它提供易于使用的 API,允许开发人员测试浏览器是否支持特定特性。这有助于为不受支持的特性提供后备方案或替代解决方案,从而增强网站或应用程序的兼容性和功能性。
什么是 Modernizr,它如何帮助进行特性检测?
Modernizr 是一个 JavaScript 库,可帮助开发人员利用 HTML5 和 CSS3 特性,同时保持与旧版浏览器的兼容性。它使用特性检测来检查浏览器是否支持特定特性,并将类添加到 HTML 元素,允许您在样式表或 JavaScript 中定位特定浏览器功能。
如何使用 device-detector-js 包进行特性检测?
device-detector-js 包是用于设备检测的强大工具。它解析用户代理字符串并检测智能手机、平板电脑、台式机、电视机等设备。它还检测浏览器、引擎、操作系统和其他有用信息。您可以使用此包根据检测到的设备调整网站或应用程序的行为。
实施特性检测的一些最佳实践是什么?
实施特性检测的一些最佳实践包括:使用可靠且经过测试的库(如 Modernizr 或 Feature.js)、在不同的浏览器和设备上彻底测试您的特性检测代码、为不受支持的特性提供替代解决方案或后备方案以及避免根据浏览器类型或版本来假设特性支持。
特性检测能否帮助提高网站性能?
是的,特性检测可以帮助提高网站性能。通过检测不受支持的特性并提供替代解决方案或后备方案,您可以防止不必要的代码在浏览器中运行。这可以减少加载时间并提高网站的整体性能。
如何了解不同浏览器支持的最新特性?
由于 Web 开发的快速发展,了解不同浏览器支持的最新特性可能具有挑战性。但是,Mozilla 开发者网络 (MDN)、Can I Use 和 JavaScript 文档等资源可以提供有关不同浏览器中特性支持的最新信息。
以上是当JavaScript功能检测失败时的详细内容。更多信息请关注PHP中文网其他相关文章!

JavaScript字符串替换方法详解及常见问题解答 本文将探讨两种在JavaScript中替换字符串字符的方法:在JavaScript代码内部替换和在网页HTML内部替换。 在JavaScript代码内部替换字符串 最直接的方法是使用replace()方法: str = str.replace("find","replace"); 该方法仅替换第一个匹配项。要替换所有匹配项,需使用正则表达式并添加全局标志g: str = str.replace(/fi

本文讨论了在浏览器中优化JavaScript性能的策略,重点是减少执行时间并最大程度地减少对页面负载速度的影响。

本文讨论了使用浏览器开发人员工具的有效JavaScript调试,专注于设置断点,使用控制台和分析性能。

将矩阵电影特效带入你的网页!这是一个基于著名电影《黑客帝国》的酷炫jQuery插件。该插件模拟了电影中经典的绿色字符特效,只需选择一张图片,插件就会将其转换为充满数字字符的矩阵风格画面。快来试试吧,非常有趣! 工作原理 插件将图片加载到画布上,读取像素和颜色值: data = ctx.getImageData(x, y, settings.grainSize, settings.grainSize).data 插件巧妙地读取图片的矩形区域,并利用jQuery计算每个区域的平均颜色。然后,使用

本文将引导您使用jQuery库创建一个简单的图片轮播。我们将使用bxSlider库,它基于jQuery构建,并提供许多配置选项来设置轮播。 如今,图片轮播已成为网站必备功能——一图胜千言! 决定使用图片轮播后,下一个问题是如何创建它。首先,您需要收集高质量、高分辨率的图片。 接下来,您需要使用HTML和一些JavaScript代码来创建图片轮播。网络上有很多库可以帮助您以不同的方式创建轮播。我们将使用开源的bxSlider库。 bxSlider库支持响应式设计,因此使用此库构建的轮播可以适应任何

数据集对于构建API模型和各种业务流程至关重要。这就是为什么导入和导出CSV是经常需要的功能。在本教程中,您将学习如何在Angular中下载和导入CSV文件

核心要点 利用 JavaScript 增强结构化标记可以显着提升网页内容的可访问性和可维护性,同时减小文件大小。 JavaScript 可有效地用于为 HTML 元素动态添加功能,例如使用 cite 属性自动在块引用中插入引用链接。 将 JavaScript 与结构化标记集成,可以创建动态用户界面,例如无需页面刷新的选项卡面板。 确保 JavaScript 增强功能不会妨碍网页的基本功能至关重要;即使禁用 JavaScript,页面也应保持功能正常。 可以使用高级 JavaScript 技术(


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

ZendStudio 13.5.1 Mac
功能强大的PHP集成开发环境

EditPlus 中文破解版
体积小,语法高亮,不支持代码提示功能

螳螂BT
Mantis是一个易于部署的基于Web的缺陷跟踪工具,用于帮助产品缺陷跟踪。它需要PHP、MySQL和一个Web服务器。请查看我们的演示和托管服务。

SublimeText3 Linux新版
SublimeText3 Linux最新版

mPDF
mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),