JavaScript判断浏览器运行环境的详细方法


Posted in Javascript onJune 30, 2019

前言

看到标题,大家就能想起这个需求在很多项目上都能用到。我们部署在Web服务器上的前端应用,既可以用PC浏览器访问,也可以用手机浏览器访问,再加上现在智能设备的推广,我们甚至能在车载系统、穿戴设备和电视平台上访问。

设备的多样化让用户无处不在,有时候我们需要根据不同的浏览器运行环境做出对应的处理。浏览器是JavaScript的承载体,我们可以从浏览器上获取相关的信息,来进一步处理我们的业务逻辑。

然而浏览器品牌众多,有些浏览器使用的标准也不太一样,造就了难以统一的判断。下面我大概罗列一下常用的浏览器品牌和在什么情况下使用浏览器运行环境判断。浏览器相关统计数据可以参考这里。

国际五大浏览器品牌:按照全球使用率降序排列

  • Google Chrome:Windows、OSX、Linux、Android、iOS
  • Apple Safari:OSX、iOS
  • Mozilla Firefox:Windows、OSX、Linux、Android、iOS
  • ASA Opera:Windows、OSX、Linux、Android、iOS
  • Microsoft Internet Explorer或Microsoft Edge:Windows

国产常用浏览器品牌:按照国内使用率降序排列,普遍基于开源项目Chromium进行开发

  • 微信浏览器
  • QQ浏览器
  • UC浏览器
  • 2345浏览器
  • 搜狗浏览器
  • 猎豹浏览器
  • 遨游浏览器
  • 百度浏览器:百度在2019年04月30日宣布停止服务
  • 其他浏览器:很多很多,数不清,我就不列出来了

顺便吐槽一下这个不要脸的红芯浏览器,明明就是基于Chromium进行二次开发再套多一层外壳,还非得说自己开发的浏览器是世界第五大浏览器,偷吃不抹嘴,还是被眼尖的网友发现了。。。。

使用场景

  • 判断用户浏览器是桌面端还是移动端,显示对应的主题样式
  • 判断用户浏览器是Android端还是iOS端,跳转到对应的App下载链接
  • 判断用户浏览器是微信端还是H5端,调用微信分享或当前浏览器分享
  • 获取用户浏览器的内核和载体,用于统计用户设备平台分布区间
  • 获取用户浏览器的载体版本,用于提示更新信息
  • 其实还有很多使用场景,就不一一举例了

原理

针对处理一个这样的使用场景,其实有一个比较专业的名字,叫做浏览器指纹。我们上面谈到的需求也只是浏览器指纹方案里面的一小部分,而我们需要使用到的浏览器指纹就是UserAgent。

这个UserAgent是何方神圣呢,中文翻译过来就是用户代理。引用百度的定义,就是一个特殊字符串头,使得服务器能够识别客户使用的操作系统及版本、CPU类型、浏览器载体及版本、浏览器渲染引擎、浏览器语言、浏览器插件等。而这些信息也足够我们去判断浏览器运行环境了。

准备

目前网上很多解决方法都只是针对系统是否是桌面端还是移动端,Android端还是iOS端,部分浏览器载体的判断和获取等等,没有一个比较完美或者终极的解决方案。

因此我用了很多测试平台整理出一个比较全面的解决方案。这个方案包含浏览器系统及版本、浏览器平台、浏览器内核及版本、浏览器载体及版本、浏览器外壳及版本。

而此方案也是基于navigator.userAgent获取相关浏览器信息(如下),再通过系统、平台、内核、载体、外壳的特有字段进行归类统一,整理出一个完整的浏览器运行环境。

const ua = navigator.userAgent.toLowerCase();

// 输出
"Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1"

浏览器信息:权重按照以下降序排列

  • 浏览器系统:所运行的操作系统,包含Windows、OSX、Linux、Android、iOS
  • 浏览器平台:所运行的设备平台,包含Desktop桌面端、Mobile移动端
  • 浏览器内核:浏览器渲染引擎,包含Webkit、Gecko、Presto、Trident
  • 浏览器载体:五大浏览器品牌,包含Chrome、Safari、Firefox、Opera、Iexplore/Edge
  • 浏览器外壳:基于五大浏览器品牌的内核进行开发,再套一层自研技术的外壳,如国内众多浏览器品牌

获取UserAgent是否包含字段:判断是否包含系统、平台、内核、载体、外壳的特有字段

const testUa = regexp => regexp.test(ua);

获取UserAgent对应字段的版本

const testVs = regexp => (ua.match(regexp) + "").replace(/[^0-9|_.]/ig, "").replace(/_/ig, ".");

方案

上述准备工作完成后,我们就按照权重(系统 + 系统版本 > 平台 > 内核 + 载体 + 内核版本 + 载体版本 > 外壳 + 外壳版本)根据系统、平台、内核、载体、外壳的特有字段来归类统一浏览器运行环境。

系统+系统版本

// 系统
let system = "unknown";
if (testUa(/windows|win32|win64|wow32|wow64/ig)) {
 system = "windows"; // window系统
} else if (testUa(/macintosh|macintel/ig)) {
 system = "osx"; // osx系统
} else if (testUa(/x11/ig)) {
 system = "linux"; // linux系统
} else if (testUa(/android|adr/ig)) {
 system = "android"; // android系统
} else if (testUa(/ios|iphone|ipad|ipod|iwatch/ig)) {
 system = "ios"; // ios系统
}

// 系统版本
let systemVs = "unknown";
if (system === "windows") {
 if (testUa(/windows nt 5.0|windows 2000/ig)) {
  systemVs = "2000";
 } else if (testUa(/windows nt 5.1|windows xp/ig)) {
  systemVs = "xp";
 } else if (testUa(/windows nt 5.2|windows 2003/ig)) {
  systemVs = "2003";
 } else if (testUa(/windows nt 6.0|windows vista/ig)) {
  systemVs = "vista";
 } else if (testUa(/windows nt 6.1|windows 7/ig)) {
  systemVs = "7";
 } else if (testUa(/windows nt 6.2|windows 8/ig)) {
  systemVs = "8";
 } else if (testUa(/windows nt 6.3|windows 8.1/ig)) {
  systemVs = "8.1";
 } else if (testUa(/windows nt 10.0|windows 10/ig)) {
  systemVs = "10";
 }
} else if (system === "osx") {
 systemVs = testVs(/os x [\d._]+/ig);
} else if (system === "android") {
 systemVs = testVs(/android [\d._]+/ig);
} else if (system === "ios") {
 systemVs = testVs(/os [\d._]+/ig);
}

平台

let platform = "unknow";
if (system === "windows" || system === "osx" || system === "linux") {
 platform = "desktop"; // 桌面端
} else if (system === "android" || system === "ios" || testUa(/mobile/ig)) {
 platform = "mobile"; // 移动端
}

内核+载体

let engine = "unknow";
let supporter = "unknow";
if (testUa(/applewebkit/ig) && testUa(/safari/ig)) {
 engine = "webkit"; // webkit内核
 if (testUa(/edge/ig)) {
  supporter = "edge"; // edge浏览器
 } else if (testUa(/opr/ig)) {
  supporter = "opera"; // opera浏览器
 } else if (testUa(/chrome/ig)) {
  supporter = "chrome"; // chrome浏览器
 } else {
  supporter = "safari"; // safari浏览器
 }
} else if (testUa(/gecko/ig) && testUa(/firefox/ig)) {
 engine = "gecko"; // gecko内核
 supporter = "firefox"; // firefox浏览器
} else if (testUa(/presto/ig)) {
 engine = "presto"; // presto内核
 supporter = "opera"; // opera浏览器
} else if (testUa(/trident|compatible|msie/ig)) {
 engine = "trident"; // trident内核
 supporter = "iexplore"; // iexplore浏览器
}

内核版本+载体版本

// 内核版本
let engineVs = "unknow";
if (engine === "webkit") {
 engineVs = testVs(/applewebkit\/[\d.]+/ig);
} else if (engine === "gecko") {
 engineVs = testVs(/gecko\/[\d.]+/ig);
} else if (engine === "presto") {
 engineVs = testVs(/presto\/[\d.]+/ig);
} else if (engine === "trident") {
 engineVs = testVs(/trident\/[\d.]+/ig);
}

// 载体版本
let supporterVs = "unknow";
if (supporter === "chrome") {
 supporterVs = testVs(/chrome\/[\d.]+/ig);
} else if (supporter === "safari") {
 supporterVs = testVs(/version\/[\d.]+/ig);
} else if (supporter === "firefox") {
 supporterVs = testVs(/firefox\/[\d.]+/ig);
} else if (supporter === "opera") {
 supporterVs = testVs(/opr\/[\d.]+/ig);
} else if (supporter === "iexplore") {
 supporterVs = testVs(/(msie [\d.]+)|(rv:[\d.]+)/ig);
} else if (supporter === "edge") {
 supporterVs = testVs(/edge\/[\d.]+/ig);
}

外壳+外壳版本

let shell = "none";
let shellVs = "unknow";
if (testUa(/micromessenger/ig)) {
 shell = "wechat"; // 微信浏览器
 shellVs = testVs(/micromessenger\/[\d.]+/ig);
} else if (testUa(/qqbrowser/ig)) {
 shell = "qq"; // QQ浏览器
 shellVs = testVs(/qqbrowser\/[\d.]+/ig);
} else if (testUa(/ubrowser/ig)) {
 shell = "uc"; // UC浏览器
 shellVs = testVs(/ubrowser\/[\d.]+/ig);
} else if (testUa(/2345explorer/ig)) {
 shell = "2345"; // 2345浏览器
 shellVs = testVs(/2345explorer\/[\d.]+/ig);
} else if (testUa(/metasr/ig)) {
 shell = "sougou"; // 搜狗浏览器
} else if (testUa(/lbbrowser/ig)) {
 shell = "liebao"; // 猎豹浏览器
} else if (testUa(/maxthon/ig)) {
 shell = "maxthon"; // 遨游浏览器
 shellVs = testVs(/maxthon\/[\d.]+/ig);
} else if (testUa(/bidubrowser/ig)) {
 shell = "baidu"; // 百度浏览器
 shellVs = testVs(/bidubrowser [\d.]+/ig);
}

终极合体

根据以上的条件判断获得的变量如下,我们可以把它们合并成一个对象输出。这样就可以输出一个清晰的浏览器运行环境,后面想干嘛就干嘛了,多方便。

本文重点探究方案的可行性,没有过多考虑到代码的优化,所以条件判断使用得有些多,如果有什么方法能优化下代码,减少条件判断,可以在下方评论提个建议哟。

  • system:系统
  • systemVs:系统版本
  • platform:平台
  • engine:内核
  • engineVs:内核版本
  • supporter:载体
  • supporterVs:载体版本
  • shell:外壳
  • shellVs:外壳版本
function BrowserType() {
 const ua = navigator.userAgent.toLowerCase();
 const testUa = regexp => regexp.test(ua);
 const testVs = regexp => (ua.match(regexp) + "").replace(/[^0-9|_.]/ig, "").replace(/_/ig, ".");
 // 接上以上if...else条件判断
 // ......
 // 获取到system、systemVs、platform、engine、engineVs、supporter、supporterVs、shell、shellVs
 return Object.assign({
  engine, // webkit gecko presto trident
  engineVs,
  platform, // desktop mobile
  supporter, // chrome safari firefox opera iexplore edge
  supporterVs,
  system, // windows osx linux android ios
  systemVs
 }, shell === "none" ? {} : {
  shell, // wechat qq uc 2345 sougou liebao maxthon baidu
  shellVs
 });
}

在控制台执行BrowserType(),该有的都出来了,哈哈!源码详情请戳这里,喜欢的可以点个赞支持下,谢谢。

JavaScript判断浏览器运行环境的详细方法

结语

写到最后总结得差不多了,后续如果我想起还有哪些判断浏览器运行环境终极方案遗漏的,会继续在这篇文章上补全,同时也希望各位倔友对文章里的要点进行补充或者提出自己的见解。欢迎在下方进行评论或补充喔,喜欢的点个赞或收个藏,保证你在开发时用得上。

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
JavaScript 学习笔记(十一)
Jan 19 Javascript
Javascript下IE与Firefox下的差异兼容写法总结
Jun 18 Javascript
基于prototype扩展的JavaScript常用函数库
Nov 30 Javascript
删除节点的jquery代码
Jan 13 Javascript
javascript中加号(+)操作符的一些神奇作用
Jun 06 Javascript
javascript中的Base64、UTF8编码与解码详解
Mar 18 Javascript
javascript中加var和不加var的区别 你真的懂吗
Jan 06 Javascript
jQueryUI中的datepicker使用方法详解
May 25 Javascript
js制作网站首页图片轮播特效代码
Aug 30 Javascript
jQuery实现的模拟弹出窗口功能示例
Nov 24 Javascript
Vue自定义过滤器格式化数字三位加一逗号实现代码
Mar 23 Javascript
详解vue 计算属性与方法跟侦听器区别(面试考点)
Apr 23 Javascript
微信小程序如何自定义table组件
Jun 29 #Javascript
微信小程序如何调用图片接口API并居中显示
Jun 29 #Javascript
微信小程序如何调用json数据接口并解析
Jun 29 #Javascript
pm2启动ssr失败的解决方法
Jun 29 #Javascript
localstorage实现带过期时间的缓存功能
Jun 28 #Javascript
vue分页器组件编写方法详解
Jun 28 #Javascript
Vue分页器实现原理详解
Jun 28 #Javascript
You might like
表单复选框向PHP传输数据的代码
2007/11/13 PHP
关于PHP的相似度计算函数:levenshtein的使用介绍
2013/04/15 PHP
PHP解决URL中文GBK乱码问题的两种方法
2014/06/03 PHP
PHP简单判断iPhone、iPad、Android及PC设备的方法
2016/10/11 PHP
jQuery 使用手册(二)
2009/09/23 Javascript
JS控件ASP.NET的treeview控件全选或者取消(示例代码)
2013/12/16 Javascript
javascript:void(0)的问题使用探讨
2014/04/10 Javascript
JavaScript检测弹出窗口是否已经关闭的方法
2015/03/24 Javascript
探究JavaScript中的五种事件处理程序方式
2016/12/07 Javascript
ajax与json 获取数据并在前台使用简单实例
2017/01/19 Javascript
浅谈js中的变量名和函数名重名
2017/02/13 Javascript
JS设计模式之数据访问对象模式的实例讲解
2017/09/30 Javascript
vue项目部署到nginx/tomcat服务器的实现
2019/08/26 Javascript
jQuery实现轮播图效果
2019/11/26 jQuery
JavaScript 引用类型实例详解【数组、对象、严格模式等】
2020/05/13 Javascript
JS使用Chrome浏览器实现调试线上代码
2020/07/23 Javascript
python二叉树遍历的实现方法
2013/11/21 Python
用ReactJS和Python的Flask框架编写留言板的代码示例
2015/12/19 Python
Python+Pika+RabbitMQ环境部署及实现工作队列的实例教程
2016/06/29 Python
python 接口_从协议到抽象基类详解
2017/08/24 Python
python 日志增量抓取实现方法
2018/04/28 Python
Windows下pycharm创建Django 项目(虚拟环境)过程解析
2019/09/16 Python
Pytorch 定义MyDatasets实现多通道分别输入不同数据方式
2020/01/15 Python
Python实现随机爬山算法
2021/01/29 Python
中专生自荐信
2013/10/12 职场文书
仓库主管的岗位职责
2013/12/04 职场文书
专业幼师实习生自我鉴定范文
2013/12/08 职场文书
酒店前厅员工辞职信
2014/01/08 职场文书
湖南省召开党的群众路线教育实践活动总结大会报告
2014/10/21 职场文书
党员个人年度总结
2015/02/14 职场文书
法人代表证明书范本
2015/06/18 职场文书
公司财务管理制度
2015/08/04 职场文书
2015年店长个人工作总结
2015/10/23 职场文书
vue3中的组件间通信
2021/03/31 Vue.js
Golang 实现超大文件读取的两种方法
2021/04/27 Golang
基于Pygame实现简单的贪吃蛇游戏
2021/12/06 Python