【问题标题】:Detecting a mobile browser检测移动浏览器
【发布时间】:2019-10-09 01:18:10
【问题描述】:

如果用户有移动浏览器,我正在寻找一个返回布尔值的函数。

我知道我可以使用navigator.userAgent 并使用正则表达式编写该函数,但用户代理对于不同的平台来说过于多样化。我怀疑匹配所有可能的设备会很容易,而且我认为这个问题已经解决了很多次,所以应该有某种完整的解决方案来完成这样的任务。

我正在查看 this site,但遗憾的是,该脚本非常神秘,我不知道如何将其用于我的目的,即创建一个返回 true / false 的函数。

【问题讨论】:

  • @Thrustmaster:真的不会。为不同的浏览器提供不同的 JS 意味着您必须将 Vary: User-Agent 添加到您的响应中,否则缓存代理将存储一个版本并将其发送到另一种浏览器。但是Vary: User-Agent 使得响应在 IE 中无法缓存。
  • @ave:你想通过检测“移动”浏览器来做什么?在当今平板电脑和混合计算设备的世界中,这种区别是有争议的。您是否希望检测小屏幕,并在这种情况下呈现不同的 UI?您是否希望检测低带宽连接?您是否希望检测触摸界面?
  • 所以我更新了我的答案以使用 detectmobilebrowsers.com javascript 方法,但如果有人仍然需要它,则返回一个布尔值。 ( 以防万一 )。快乐检测:)

标签: javascript browser-detection mobile-browser platform-detection


【解决方案1】:

使用正则表达式(来自detectmobilebrowsers.com):

这是一个使用极其冗长而全面的正则表达式的函数,它返回 truefalse 值,具体取决于用户是否使用手机浏览。

window.mobileCheck = function() {
  let check = false;
  (function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))) check = true;})(navigator.userAgent||navigator.vendor||window.opera);
  return check;
};

对于那些希望在此测试中包含平板电脑的人(尽管可以说您不应该),您可以使用以下功能:

window.mobileAndTabletCheck = function() {
  let check = false;
  (function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))) check = true;})(navigator.userAgent||navigator.vendor||window.opera);
  return check;
};

使用 navigator.userAgentData

您也可以使用navigator.userAgentData.mobile,但userAgentData 仍处于试验阶段,因此不建议在生产环境中使用。

const isMobile = navigator.userAgentData.mobile; //resolves true/false

Compatibility chart for userAgentData


原始答案

您可以通过简单地运行设备列表并检查useragent 是否与以下内容匹配来做到这一点:

  function detectMob() {
    const toMatch = [
        /Android/i,
        /webOS/i,
        /iPhone/i,
        /iPad/i,
        /iPod/i,
        /BlackBerry/i,
        /Windows Phone/i
    ];
    
    return toMatch.some((toMatchItem) => {
        return navigator.userAgent.match(toMatchItem);
    });
}

但是,由于您认为这种方法不可靠,您可以假设任何分辨率为 800x600 或以下的设备也是移动设备,从而进一步缩小了您的目标范围(尽管现在很多移动设备的分辨率比这大得多)

  function detectMob() {
    return ( ( window.innerWidth <= 800 ) && ( window.innerHeight <= 600 ) );
  }

参考:

【讨论】:

  • 您好,我刚刚访问了我的 iPad 3、iOS 6.1.2 上的 detectmobilebrowsers.com 链接,它显示“未检测到移动浏览器”。
  • @RichardLovejoy 在建站时,ipad 一般不被认为是手机。
  • 来自about 页面:Android 平板电脑、iPad、Kindle Fires 和 PlayBooks 在设计上未检测到。要添加对平板电脑的支持,请将|android|ipad|playbook|silk 添加到第一个正则表达式。
  • Google TV 也是安卓系统。什么定义了手机?屏幕尺寸 ?触碰 ?设备方向?当我设计它更多的是鼠标悬停与否,大按钮或小链接的问题。所以,现在,我用“if (Modernizr.touch)”运行:)
  • 天哪,用户代理的整个想法很糟糕,真的,真的需要停止。我们真的需要停止让客户逆流而上,只坚持媒体查询。如果他们想根据特定页面的规模进行重定向,那么只需通过 JS 检查特定媒体查询的范围,即tylergaw.com/articles/reacting-to-media-queries-in-javascript
【解决方案2】:

这里有一个userAgent解决方案,比match更高效...

function _isMobile(){
    // if we want a more complete list use this: http://detectmobilebrowsers.com/
    // str.test() is more efficent than str.match()
    // remember str.test is case sensitive
    var isMobile = (/iphone|ipod|android|ie|blackberry|fennec/).test
         (navigator.userAgent.toLowerCase());
    return isMobile;
}

【讨论】:

  • 测试方法不区分大小写,但您的正则表达式是。您可以在末尾使用“i”标记不区分大小写的正则表达式,然后执行/iphone|etc/i.test(navigator.userAgent)
【解决方案3】:
var isMobile = {
    Android: function() {
        return navigator.userAgent.match(/Android/i);
    },
    BlackBerry: function() {
        return navigator.userAgent.match(/BlackBerry/i);
    },
    iOS: function() {
        return navigator.userAgent.match(/iPhone|iPad|iPod/i);
    },
    Opera: function() {
        return navigator.userAgent.match(/Opera Mini/i);
    },
    Windows: function() {
        return navigator.userAgent.match(/IEMobile/i) || navigator.userAgent.match(/WPDesktop/i);
    },
    any: function() {
        return (isMobile.Android() || isMobile.BlackBerry() || isMobile.iOS() || isMobile.Opera() || isMobile.Windows());
    }
};

如何使用

if( isMobile.any() ) alert('Mobile');

检查用户是否在特定的移动设备上:

if( isMobile.iOS() ) alert('iOS');

参考:http://www.abeautifulsite.net/blog/2011/11/detecting-mobile-devices-with-javascript

github上的增强版:https://github.com/smali-kazmi/detect-mobile-browser

【讨论】:

  • 为什么不让 any() 成为 ORed isMobile 成员的 for...in 循环?
  • @ChristopherW 我按照您的建议创建了它的插件并修改了代码
  • @Rob_vH 我已将此代码放入 github (github.com/smali-kazmi/detect-mobile-browser) 并具有一些高级功能;你也愿意在那里发送建议
  • 这个内容得到了我的支持,但我正试图弄清楚如何将其转换为 John Papa 的样式并且遇到了一些困难。 AngularJS 作为一个整体(大约一个月后了解它)和 vm.js 仍然很新。符号使学习曲线向上倾斜一点。有什么帮助吗? -C§ 编辑:我正在尝试用 karma-jasmine 对其进行单元测试,这就是我问的原因。
  • @AkarshSatija 这 5 次正则表达式检查的性能下降是否会影响您的任何应用程序?如果确实如此,我会感到非常惊讶。过早的优化可能会浪费时间......
【解决方案4】:

怎么样:

if (typeof screen.orientation !== 'undefined') { ... }

...因为智能手机通常支持此属性而桌面浏览器不支持。请参阅MDN

编辑 1: 正如@Gajus 指出的那样,window.orientation 现在已弃用,不应使用。

编辑 2:您可以使用实验性的 screen.orientation 代替已弃用的 window.orientation。见MDN

编辑 3:从 window.orientation 更改为 screen.orientation

【讨论】:

  • 这实际上是超级独特和令人敬畏的,你介意我将它添加到我的答案中吗?
  • 这可能不会长期有效。 1) 平板电脑可以有不错的屏幕尺寸,您希望它们显示完整的桌面网站,但它们将具有此属性 2) Windows 8 已经到来,并带有一堆带有触摸屏和旋转屏幕的笔记本电脑。
  • 关于屏幕尺寸不错的平板电脑的第一点-我认为您也可以对所有其他解决方案提出相同的论点(大屏幕平板电脑被跟踪为小屏幕)。无论如何,这里的想法是搜索由小型设备共享的属性,而不是保持长代码并为每个新的设备/版本/模型添加正则表达式。我认为设备检测属于过去,今天我们需要专注于特征检测。再次,我很高兴在这里找到更合适的房产...
  • window.orientation 是一个已弃用的属性(developer.mozilla.org/en-US/docs/Web/API/Window/orientationcompat.spec.whatwg.org/#dom-window-orientation),一些移动浏览器出于未知原因选择支持该属性。相同的浏览器实现window.screen.orientation(也在桌面浏览器中定义)。我只能假设 window.orientation 是出于遗留原因而留在那里的,因此不应在新应用程序中使用。
  • screen.orientation 也支持桌面developer.mozilla.org/en-US/docs/Web/API/Screen/…
【解决方案5】:

功能检测比试图找出您正在使用的设备要好得多,而且很难跟上一直出现的新设备,Modernizr 之类的库可以让您知道某个特定功能是否可用.

【讨论】:

  • 您回答了另一个问题,而不是所问的问题。而不是“我如何检测移动设备?”,您回答的是“我如何检测某些功能?”。并非所有设备检测都用于特征检测。如果我们希望获得有关设备的统计信息怎么办?那么不,“特征检测”并不“比[找出设备]好得多”。
  • 这不是答案,但不仅仅是评论。问题是:您为什么要检测浏览器,然后您可能想知道它,因为仅(缺少)触摸。在大多数情况下,响应式网页设计就足够了。
  • 如果我要检测的功能是设备 CPU 的强大程度怎么办?我需要降低手机的质量...
【解决方案6】:

为了添加额外的控制层,我使用 HTML5 存储来检测它是使用移动存储还是桌面存储。如果浏览器不支持存储,我有一个移动浏览器名称数组,并将用户代理与数组中的浏览器进行比较。

这很简单。这是函数:

// Used to detect whether the users browser is an mobile browser
function isMobile() {
    ///<summary>Detecting whether the browser is a mobile browser or desktop browser</summary>
    ///<returns>A boolean value indicating whether the browser is a mobile browser or not</returns>

    if (sessionStorage.desktop) // desktop storage 
        return false;
    else if (localStorage.mobile) // mobile storage
        return true;

    // alternative
    var mobile = ['iphone','ipad','android','blackberry','nokia','opera mini','windows mobile','windows phone','iemobile']; 
    for (var i in mobile) if (navigator.userAgent.toLowerCase().indexOf(mobile[i].toLowerCase()) > 0) return true;

    // nothing found.. assume desktop
    return false;
}

【讨论】:

  • 我还没有在移动设备上测试过,但sessionStorage.desktop 在 Safari、Chrome 或 Firefox 中都不存在(发布时所有最新版本)。但是,您会获得赞成票,因为您的解决方案比其他解决方案朝着更好的方向发展。但不要忘记使用var mobile = 而不是mobile =
  • 在不支持该方法的旧浏览器中不要使用 indexOf 或者使用 polyfill 也是一个好主意。没有必要在小写值列表上使用 toLowerCase,如果您正在运行 /ipad|iphone|etc/i.test(navigator.userAgent) 而不是上面的慢循环,也没有必要这样做。
【解决方案7】:

最好的一定是:

var isMobile = (/Mobile/i.test(navigator.userAgent));

但就像 Yoav Barnea 所说的那样......

// Seem legit
var isMobile = ('DeviceOrientationEvent' in window || 'orientation' in window);
// But with my Chrome on windows, DeviceOrientationEvent == fct()
if (/Windows NT|Macintosh|Mac OS X|Linux/i.test(navigator.userAgent)) isMobile = false;
// My android have "linux" too
if (/Mobile/i.test(navigator.userAgent)) isMobile = true;

经过这 3 次测试,我希望 var isMobile 是...好的

【讨论】:

  • > Android 上的 Firefox 移动版似乎没有“窗口中的‘方向’”
  • 对不起.. 对我来说没问题,现在它工作得很好。 “如果 (Modernizr.touch) /* ... */ ” 然后继续...
  • 只是想知道 Modernizr.touch 在触摸屏桌面设备上如何工作。
  • 为了让它更优雅,你应该把所有的代码都放在一个 if-else if-else if 块中。
【解决方案8】:

这是他的全部功能

function isMobile(){
    return (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino|android|ipad|playbook|silk/i.test(navigator.userAgent||navigator.vendor||window.opera)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test((navigator.userAgent||navigator.vendor||window.opera).substr(0,4)))
}

jQuery.noConflict();
jQuery(document).ready(function(){
    if(isMobile()) alert("Mobile"); else alert("Not Mobile");
});

【讨论】:

  • .substr(0,4) 返回前 4 个字母。它如何检测“android.+mobile”?
  • @raacer 答案中实际上有两个正则表达式(都在同一行)-第一个检查整个 UA 字符串,并查找 android、mobile 等,而第二个仅检查针对 UA 的前 4 个字符。
  • 成功了!非常感谢。
【解决方案9】:

这里有一个来自facebook's slingshot来源的简单解决方案

var isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
if (isMobile) {
  /* your code here */
}

【讨论】:

  • 不错。在某些情况下非常有用
  • 对于检测可以安装移动应用程序的设备的情况很有用。您本身并不关心浏览器。只是设备/操作系统。
  • 整洁! 2021 年仍然有效,尽管我现在要添加 let isMobile=
  • 适用于 Windows Phone / webOS / 黑莓?
【解决方案10】:

这样的事情怎么样?

if(
    (screen.width <= 640) || 
    (window.matchMedia && 
     window.matchMedia('only screen and (max-width: 640px)').matches
    )
  ){
   // Do the mobile thing
}

【讨论】:

  • 为什么不直接使用screen.width呢?在我看来,这比window.matchMedia 更可靠。
  • 好点约翰,我不记得我当时在想什么,如果第一个子句是假的,第二个子句似乎不太可能返回真(现在看)。不过我添加它一定有什么原因。
  • 大多数体面的程序员在看到一年前自己编写的代码时都会感到羞愧。那些不仅没有成长为程序员的人;-)
  • 窗口分辨率与浏览器是否在移动设备上无关。例如,许多桌面浏览器在非全屏窗口中运行。如果您向这些浏览器展示专为手持屏幕设计的 UI,他们的用户将会有一种令人沮丧的体验。
【解决方案11】:

这是我重新思考的问题解决方案。仍然不完美。唯一真正的解决方案是设备制造商开始认真对待“Mobile”和“Tablet”用户代理字符串。

window.onload = userAgentDetect;
function userAgentDetect() {
  if(window.navigator.userAgent.match(/Mobile/i)
  || window.navigator.userAgent.match(/iPhone/i)
  || window.navigator.userAgent.match(/iPod/i)
  || window.navigator.userAgent.match(/IEMobile/i)
  || window.navigator.userAgent.match(/Windows Phone/i)
  || window.navigator.userAgent.match(/Android/i)
  || window.navigator.userAgent.match(/BlackBerry/i)
  || window.navigator.userAgent.match(/webOS/i)) {
    document.body.className += ' mobile';
    alert('True - Mobile - ' + navigator.userAgent);
  } else {
    alert('False - Mobile - ' + navigator.userAgent);
  }
  if(window.navigator.userAgent.match(/Tablet/i)
  || window.navigator.userAgent.match(/iPad/i)
  || window.navigator.userAgent.match(/Nexus 7/i)
  || window.navigator.userAgent.match(/Nexus 10/i)
  || window.navigator.userAgent.match(/KFAPWI/i)) {
    document.body.className -= ' mobile';
    document.body.className += ' tablet';
    alert('True - Tablet - ' + navigator.userAgent);
  } else {
    alert('False - Tablet - ' + navigator.userAgent);
  }
}

当 Nexus 7 平板电脑只有 Android UA 字符串时会发生什么?首先Mobile变为true,之后Tablet也变为true,但是Tablet会从body标签中删除Mobile UA字符串。

CSS:

body.tablet { background-color: green; }
body.mobile { background-color: red; }

alert 添加用于开发的行。 Chrome 控制台可以模拟许多手持设备。在那里测试。

编辑:

不要使用这个,而是使用特征检测。市场上有如此多的设备和品牌,以品牌为目标永远不会是正确的解决方案。

【讨论】:

  • “别用这个” ?您可以随时删除您的答案。另外,所有那些.match( ...嗯。 RegExp 和.test() 是一个更简单的变体。
【解决方案12】:

检测JS代码是否在移动浏览器上执行没有完美的解决方案,但以下两个选项在大多数情况下应该可以工作。

选项 1:浏览器嗅探

!function(a){var b=/iPhone/i,c=/iPod/i,d=/iPad/i,e=/(?=.*\bAndroid\b)(?=.*\bMobile\b)/i,f=/Android/i,g=/(?=.*\bAndroid\b)(?=.*\bSD4930UR\b)/i,h=/(?=.*\bAndroid\b)(?=.*\b(?:KFOT|KFTT|KFJWI|KFJWA|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|KFARWI|KFASWI|KFSAWI|KFSAWA)\b)/i,i=/IEMobile/i,j=/(?=.*\bWindows\b)(?=.*\bARM\b)/i,k=/BlackBerry/i,l=/BB10/i,m=/Opera Mini/i,n=/(CriOS|Chrome)(?=.*\bMobile\b)/i,o=/(?=.*\bFirefox\b)(?=.*\bMobile\b)/i,p=new RegExp("(?:Nexus 7|BNTV250|Kindle Fire|Silk|GT-P1000)","i"),q=function(a,b){return a.test(b)},r=function(a){var r=a||navigator.userAgent,s=r.split("[FBAN");return"undefined"!=typeof s[1]&&(r=s[0]),s=r.split("Twitter"),"undefined"!=typeof s[1]&&(r=s[0]),this.apple={phone:q(b,r),ipod:q(c,r),tablet:!q(b,r)&&q(d,r),device:q(b,r)||q(c,r)||q(d,r)},this.amazon={phone:q(g,r),tablet:!q(g,r)&&q(h,r),device:q(g,r)||q(h,r)},this.android={phone:q(g,r)||q(e,r),tablet:!q(g,r)&&!q(e,r)&&(q(h,r)||q(f,r)),device:q(g,r)||q(h,r)||q(e,r)||q(f,r)},this.windows={phone:q(i,r),tablet:q(j,r),device:q(i,r)||q(j,r)},this.other={blackberry:q(k,r),blackberry10:q(l,r),opera:q(m,r),firefox:q(o,r),chrome:q(n,r),device:q(k,r)||q(l,r)||q(m,r)||q(o,r)||q(n,r)},this.seven_inch=q(p,r),this.any=this.apple.device||this.android.device||this.windows.device||this.other.device||this.seven_inch,this.phone=this.apple.phone||this.android.phone||this.windows.phone,this.tablet=this.apple.tablet||this.android.tablet||this.windows.tablet,"undefined"==typeof window?this:void 0},s=function(){var a=new r;return a.Class=r,a};"undefined"!=typeof module&&module.exports&&"undefined"==typeof window?module.exports=r:"undefined"!=typeof module&&module.exports&&"undefined"!=typeof window?module.exports=s():"function"==typeof define&&define.amd?define("isMobile",[],a.isMobile=s()):a.isMobile=s()}(this);

alert(isMobile.any ? 'Mobile' : 'Not mobile');

这个特定的浏览器嗅探代码是a library called isMobile 的代码。


选项 2:window.orientation

测试是否定义了window.orientation

var isMobile = window.orientation > -1;
alert(isMobile ? 'Mobile' : 'Not mobile');

注意

并非所有触摸屏设备都是移动设备,反之亦然。所以,如果你想专门为触摸屏实现一些东西,你不应该测试你的浏览器是否在移动设备上运行,而是测试设备是否支持触摸屏:

var hasTouchscreen = 'ontouchstart' in window;
alert(hasTouchscreen ? 'has touchscreen' : 'doesn\'t have touchscreen');

【讨论】:

  • 定位方法真的很好! ))
  • 我喜欢你的 window.orientation 解决方案,但文档说它已被弃用! developer.mozilla.org/en-US/docs/Web/API/Window/orientation
  • 方向方法不好,因为 Windows 8 和更高版本可以改变方向。
  • Windows 8 和更新版本专注于添加对移动设备以及混合设备(可以转换为大垫子的笔记本电脑)的支持,这就是为什么即使 moz 没有将其称为定向检测方法也失败的原因已弃用。
  • 它来自安装了图形软件的 Win 7 可以更改方向但问自己一个问题,谁可以在台式机/笔记本电脑上使用另一个屏幕方向,例如纵向而不是横向,并使用 i 超过 1 分钟.没有人 !!!在桌面上更改方向意味着您将开始从下到上阅读屏幕上的字符。
【解决方案13】:

这也可能是一个解决方案。

var isMobile = false; //initiate as false

  // device detection
  if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|ipad|iris|kindle|Android|Silk|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(navigator.userAgent) 
  || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(navigator.userAgent.substr(0,4))) isMobile = true;

  console.log('Mobile device:'+isMobile);

  var doc_h = $(document).height(); // returns height of HTML document
  var doc_w = $(document).width(); // returns width of HTML document
  console.log('Height: '+doc_h);
  console.log('width: '+doc_w);

  var iPadVertical = window.matchMedia("(width: 768px) and (height: 1024px) and (orientation: portrait)");
  var iPadHoricontal = window.matchMedia("(width: 1024px) and (height: 767px) and (orientation: landscape)");

  console.log('Height: '+doc_h);
  console.log('width: '+doc_w);

  if (iPadVertical.matches) {
      console.log('Ipad vertical detected');
  }else if (iPadHoricontal.matches){
      console.log('Ipad horicontal detected');
  }else {
      console.log('No Ipad');
  }

如果您同时使用这两种方法,您将获得检测不同设备的完美方法。

【讨论】:

    【解决方案14】:

    来这里是为了寻找一种简单、干净的方法来检测“触摸屏设备”,我将其归类为移动设备和平板电脑。在当前答案中没有找到一个干净的选择,但确实解决了以下问题,这也可能对某人有所帮助。

    var touchDevice = ('ontouchstart' in document.documentElement);
    

    编辑:要同时支持带有触摸屏的桌面和移动设备,您可以使用以下内容:

    var touchDevice = (navigator.maxTouchPoints || 'ontouchstart' in document.documentElement);
    

    【讨论】:

    • 如果桌面显示器支持触控呢?
    • @HappyCoder 我相信操作系统会在桌面上的触摸屏处于活动状态时告诉浏览器。所以,是的,这个检查应该仍然有效。
    • (+1),但是,我现在使用的桌面有一个触摸屏,并且对于touchstart|end|etc 并不总是一致的。
    • 引导日期选择器使用以下内容: if ( window.navigator.msMaxTouchPoints || 'ontouchstart' in document) { this.input.blur(); }
    • @J.T.Taylor 看起来微软是recommendingnavigator.maxTouchPoints(没有ms前缀)。还有一个MDN article 可以查看。
    【解决方案15】:
    //true / false
    function isMobile()
    {
       return (/Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent) ); 
    }
    

    您也可以按照本教程来检测特定的手机。点击here

    【讨论】:

    • 请将Mobile添加到您的RX
    【解决方案16】:

    我建议您查看http://wurfl.io/

    简而言之,如果你导入一个很小的 ​​JS 文件:

    <script type='text/javascript' src="//wurfl.io/wurfl.js"></script>
    

    您将得到一个如下所示的 JSON 对象:

    {
     "complete_device_name":"Google Nexus 7",
     "is_mobile":true,
     "form_factor":"Tablet"
    }
    

    (当然,这是假设您使用的是 Nexus 7)并且您将能够执行以下操作:

    if(WURFL.form_factor == "Tablet"){
        //dostuff();
    }
    

    这就是你要找的。​​p>

    免责声明:我为提供这项免费服务的公司工作。谢谢。

    【讨论】:

    • 为什么这不能识别 iphone 上的 safari?
    • 您能否详细说明您正在使用的浏览器(确切的 UA 字符串将是完美的),您正在获取什么数据以及您期望什么?
    • 我也试过 wurfl,我在运行 IOS 11.2 的 iPhone 5C 上。它没有将 Safari 识别为移动浏览器。我期待使用 "is_mobile" : true 然后 "form_factor": Smartphone 并且它也没有返回。
    • 我不得不求助于公司的移动数据专家,他们告诉我 OS 11.2 不能在 5C 上运行。最低的设备是5S。所以你写的东西有问题。请随时与 ScientiaMobile 离线联系,以验证可能断开连接的位置。谢谢
    【解决方案17】:

    使用“window.screen.width”怎么样?

    if (window.screen.width < 800) {
    // do something
    }
    

    if($(window).width() < 800) {
    //do something
    }
    

    我想这是最好的方式,因为每天都有新的移动设备!

    (虽然我认为旧浏览器不支持它,但请尝试一下:))

    【讨论】:

    • 景观是什么?
    • 这对于某些场景不是很有用。如果调整桌面浏览器的大小,它可能会被错误地检测为移动浏览器
    • PC 与移动设备在可用性上有着本质的区别,糟糕的回答!!
    【解决方案18】:

    这是一个 ECMAScript 6 解决方案(TypeScript 就绪)

    public isMobile(): boolean {
      let check = false;
      ((a => {
          if (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0, 4))) check = true;
          }))(navigator.userAgent || navigator.vendor);
      return check;
     }
    

    【讨论】:

    • 为什么不直接返回 if 条件而不是整个 check 变量?
    【解决方案19】:

    在任何情况下,检查设备类型必须只调用一次:您的手机不会在一瞬间停留在桌面上:)

    所以,前段时间在这里建议的 userAgent 检查代码必须是这样的:

    (function(a){window.isMobile = (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4)))})(navigator.userAgent||navigator.vendor||window.opera);
    
    console.info('This is %s device', window.isMoblie ? 'mobile' : 'desktop');

    【讨论】:

      【解决方案20】:

      请注意,现在大多数新一代移动设备的分辨率都大于 600x400。即,iPhone 6....

      测试证明: 在这里运行最受好评和最新的帖子,运行一次可选检查,如下所示:

      (function(a){
          window.isMobile = (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4)))
      })(navigator.userAgent||navigator.vendor||window.opera);
      
      alert("This browser was found to be a % browser.", window.isMobile ? 'mobile' : 'desktop');
      

      不知何故,以下浏览器应用程序返回了以下结果。规格:iPhone 6S,iOS 10.3.1。

      Safari(最新):将其检测为移动设备。

      Chrome(最新):未将其检测为移动设备。

      所以,然后我测试了来自 Lanti (https://stackoverflow.com/a/31864119/7183483) 的建议,它确实返回了正确的结果(适用于所有 iOS 设备的移动设备,适用于我的 Mac 设备的桌面设备)。因此,我继续对其进行了一些编辑,因为它会触发两次(对于移动设备和平板电脑)。然后我注意到在 iPad 上进行测试时,它也作为移动设备返回,这是有道理的,因为 Lanti 使用的参数比任何东西都更能检查操作系统。因此,我只是将平板电脑 IF 语句移到了移动检查中,如果平板检查是否定的,则返回移动,否则返回平板。然后我为移动检查添加了 else 子句以返回为台式机/笔记本电脑,因为两者都符合条件,但随后注意到浏览器检测到 CPU 和操作系统品牌。所以我添加了那里返回的内容作为 else if 语句的一部分。为了限制它,我添加了一个警告 else 声明,以防没有检测到。 见下文,将很快在 Windows 10 PC 上进行测试更新。

      哦,我还添加了一个“debugMode”变量,以便在调试和正常编译之间轻松切换。

      免责声明:完全归功于Lanti,而且这还没有在 Windows 平板电脑上进行测试......这可能会返回台式机/笔记本电脑,因为操作系统是纯 Windows。一旦我找到使用它的朋友就会检查。

      function userAgentDetect() {
          let debugMode = true;
          if(window.navigator.userAgent.match(/Mobile/i)
              || window.navigator.userAgent.match(/iPhone/i)
              || window.navigator.userAgent.match(/iPod/i)
              || window.navigator.userAgent.match(/IEMobile/i)
              || window.navigator.userAgent.match(/Windows Phone/i)
              || window.navigator.userAgent.match(/Android/i)
              || window.navigator.userAgent.match(/BlackBerry/i)
              || window.navigator.userAgent.match(/webOS/i)) {
              if (window.navigator.userAgent.match(/Tablet/i)
                  || window.navigator.userAgent.match(/iPad/i)
                  || window.navigator.userAgent.match(/Nexus 7/i)
                  || window.navigator.userAgent.match(/Nexus 10/i)
                  || window.navigator.userAgent.match(/KFAPWI/i)) {
                  window.deviceTypeVar = 'tablet';
                  if (debugMode === true) {
                      alert('Device is a tablet - ' + navigator.userAgent);
                  }
              } else {
                  if (debugMode === true) {
                      alert('Device is a smartphone - ' + navigator.userAgent);
                  };
                  window.deviceTypeVar = 'smartphone';
              }
          } else if (window.navigator.userAgent.match(/Intel Mac/i)) {
              if (debugMode === true) {
                  alert('Device is a desktop or laptop- ' + navigator.userAgent);
              }
              window.deviceTypeVar = 'desktop_or_laptop';
          } else if (window.navigator.userAgent.match(/Nexus 7/i)
              || window.navigator.userAgent.match(/Nexus 10/i)
              || window.navigator.userAgent.match(/KFAPWI/i)) {
              window.deviceTypeVar = 'tablet';
              if (debugMode === true) {
                  alert('Device is a tablet - ' + navigator.userAgent);
              }
          } else {
              if (debugMode === true) {
                  alert('Device is unknown- ' + navigator.userAgent);
              }
              window.deviceTypeVar = 'Unknown';
          }
      }
      

      【讨论】:

        【解决方案21】:

        一旦元素获得焦点,您会立即对其进行模糊处理。 Bootstrap-datepicker 是一个非常流行且维护良好的组件,在 GitHub 上拥有近 10,000 颗星,它使用了这种方法:

        if (window.navigator.maxTouchPoints || 'ontouchstart' in document) {
            this.input.blur();
        }
        

        https://github.com/uxsolutions/bootstrap-datepicker

        感谢Tigger 的帮助。

        【讨论】:

          【解决方案22】:

          根据MDN's article on Browser detection using the user agent,鼓励尽可能避免这种方法,并建议其他途径,例如特征检测。

          但是,如果必须使用用户代理来检测设备是否为移动设备,他们建议:

          总之,我们建议在 用于检测移动设备的用户代理。

          因此,这一行就足够了:

          const isMobileDevice = window.navigator.userAgent.toLowerCase().includes("mobi");

          [更新]:

          正如@zenw0lf 在 cmets 中建议的那样,使用正则表达式会更好:

          const isMobileDevice = /Mobi/i.test(window.navigator.userAgent)

          【讨论】:

          • .includes IE-11 不支持
          • @PashaOleynik 一个 polyfill 可以解决这个问题
          • 搭载 Android 的 Nexus 7 平板电脑的用户代理字符串中没有 Mobile
          • @AlexSorokoletov 也为 MDN 文章 If the device is large enough that it's not marked with “Mobi”, you should serve your desktop site (which, as a best practice, should support touch input anyway, as more desktop machines are appearing with touchscreens).
          • 我认为这在没有 polyfill 的任何地方都可以工作:const isMobile = /Mobi/.test(window.navigator.userAgent)
          【解决方案23】:

          我通常发现检查仅在移动视图上可见的特定元素(例如汉堡图标)的可见性的更简单方法效果很好,并且比依赖非常复杂的正则表达式更安全。这将很难 100% 测试作品。

          function isHidden(el) {
             return (el.offsetParent === null);
          }
          

          【讨论】:

            【解决方案24】:

            这只是我在项目中使用的accepted answer 的一个 es6 端口。请注意,这也包括平板电脑。

            export const isMobile = () => {
              const vendor = navigator.userAgent || navigator.vendor || window.opera;
            
              return !!(
                /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(
                  vendor
                ) ||
                /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw-(n|u)|c55\/|capi|ccwa|cdm-|cell|chtm|cldc|cmd-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc-s|devi|dica|dmob|do(c|p)o|ds(12|-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(-|_)|g1 u|g560|gene|gf-5|g-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd-(m|p|t)|hei-|hi(pt|ta)|hp( i|ip)|hs-c|ht(c(-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i-(20|go|ma)|i230|iac( |-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|-[a-w])|libw|lynx|m1-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|-([1-8]|c))|phil|pire|pl(ay|uc)|pn-2|po(ck|rt|se)|prox|psio|pt-g|qa-a|qc(07|12|21|32|60|-[2-7]|i-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h-|oo|p-)|sdk\/|se(c(-|0|1)|47|mc|nd|ri)|sgh-|shar|sie(-|m)|sk-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h-|v-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl-|tdg-|tel(i|m)|tim-|t-mo|to(pl|sh)|ts(70|m-|m3|m5)|tx-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas-|your|zeto|zte-/i.test(
                  vendor.substr(0, 4)
                )
              );
            };
            

            【讨论】:

              【解决方案25】:

              有一个简单的技巧可以检测它是否是移动设备。只需检查 ontouchstart 事件是否存在:

              function isMobile()
              {
                  return "ontouchstart" in window;
              }
              

              【讨论】:

              • 不适用于带触摸屏显示器的笔记本电脑和台式电脑。 Surface 等混合电脑也会出现问题。台式机的问题不大,但现在销售的触摸屏笔记本电脑越来越多。
              【解决方案26】:

              检测移动设备或平板设备的一个非常好的方法是查看浏览器是否可以创建触摸事件。

              纯 JavaScript 代码:

              function isMobile() {
                 try{ document.createEvent("TouchEvent"); return true; }
                 catch(e){ return false; }
              }
              
              if (isMobile()) {
                 # do whatever you wanna do!
              }
              

              这对我来说非常有效,但是带有触摸屏显示器的笔记本电脑设备可能会出现问题。

              我不确定触摸屏笔记本电脑是否会被检测为移动设备,因为我尚未对其进行测试。

              【讨论】:

              • 触摸屏笔记本电脑将被检测为移动设备。以及用于台式机的触摸屏显示器。信不信由你,如果您使用触摸屏设备 RDP 到另一个没有触摸屏的设备,您也会遇到问题。
              • @blissfool 我想这将不是检测移动设备的正确方法。
              • 不幸的是,没有。但是,对于非常有限的用例,它可能仍然是一个可行的选择。
              • 永远不要编写基于异常的代码,在任何情况下都会被抛出...
              • @Sivic 只有在 TouchEvent 不存在并且上面的代码捕获它并返回 false 时才会抛出它。在移动设备、平板电脑或其他触摸屏设备上并非如此。
              【解决方案27】:

              return 'ontouchstart' in window &amp;&amp; window.screen.availWidth &lt; 768

              这个怎么样,它扩展了上面的答案,但也检查了屏幕大小

              【讨论】:

                【解决方案28】:

                不要使用此方法,因为 window.orientation 现在已弃用!!!

                function isMobile() {
                  return (typeof window.orientation !== "undefined") || (navigator.userAgent.indexOf('IEMobile') !== -1);
                };
                

                【讨论】:

                • window.orientationdeprecated。不再推荐此功能。尽管某些浏览器可能仍然支持它,但它可能已经从相关的 Web 标准中删除,可能正在被删除,或者可能仅出于兼容性目的而保留。避免使用它,并尽可能更新现有代码;请参阅本页底部的兼容性表以指导您的决定。请注意,此功能可能随时停止工作。
                【解决方案29】:

                正如许多人所说,依赖用户代理数据的移动目标是有问题的。计算屏幕尺寸也是如此。

                我的方法是借用 CSS 技术来确定界面是否是触摸的:

                仅使用 javascript(所有现代浏览器都支持),media query 匹配可以轻松推断设备是否为移动

                function isMobile() {
                    var match = window.matchMedia || window.msMatchMedia;
                    if(match) {
                        var mq = match("(pointer:coarse)");
                        return mq.matches;
                    }
                    return false;
                }
                

                【讨论】:

                • 带触控显示屏的笔记本电脑怎么样?
                • 我会检查 !matchMedia("(any-pointer:fine)").matches 自己。 (“没有插入鼠标”,而不是“有触摸屏”。
                • 这可行,而我的上一个脚本会被使用浏览器缩放功能的人欺骗(例如,我在 13" 屏幕上与 4K 交谈的人下降到 1080p 并且仍然必须使用缩放) . 在我的 iPhone (Safari/Firefox) 和 Android 设备 (Waterfox/Chrome/"Browser") 上工作。绝对比所有投票率更高的答案更可靠。
                • 在我补充了 navigator.userAgent.toLowerCase().indexOf('fennec') > -1 的 Android 上没有检测到 FireFox fennec(也许不是最好的补充......)
                • 另外你可以测试悬停属性:对于智能手机和触摸屏@media(悬停:无)和(指针:粗略)
                【解决方案30】:

                取决于用例。所有移动设备都需要电池。如果您追求的是计算能力而不耗尽电池,请使用Battery Status API

                navigator.getBattery().then(battery => {
                  battery.charging ? 'charging' : 'not charging';
                });
                

                如果您要查找的是演示文稿,请使用 matchMedia,它会返回一个布尔值:

                if (window.matchMedia("(min-width: 400px)").matches) {
                  /* the viewport is at least 400 pixels wide */
                } else {
                  /* the viewport is less than 400 pixels wide */
                }
                

                或者将它们结合起来,在平板设备上获得更好的用户体验。

                【讨论】:

                • 请注意,电池状态 API 正在从浏览器中删除。
                • 电池状态 API 从 Firefox 中删除,但仍是 W3C 候选推荐 since July 2016,继续在流行的浏览器中运行,is useful 用于塑造体验。
                • 检查电池,很聪明
                猜你喜欢
                • 2011-10-01
                • 2011-04-18
                • 2015-09-26
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2012-04-06
                • 1970-01-01
                相关资源
                最近更新 更多