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 相关文章推荐
!DOCTYPE声明对JavaScript的影响分析
Apr 12 Javascript
jquery对table中各数据的增加、保存、删除操作示例
May 14 Javascript
面向切面编程(AOP)的理解
May 01 Javascript
JS版元素周期表实现方法
Aug 05 Javascript
如何实现移动端浏览器不显示 pc 端的广告
Oct 15 Javascript
jquery实现横向图片轮播特效代码分享
Nov 19 Javascript
微信小程序表单弹窗实例
Jul 19 Javascript
vue仿element实现分页器效果
Sep 13 Javascript
JS实现百度搜索框关键字推荐
Feb 17 Javascript
webpack中的模式(mode)使用详解
Feb 20 Javascript
一分钟学会JavaScript中的try-catch
Dec 14 Javascript
Jquery+javascript实现支付网页数字键盘
Dec 21 jQuery
微信小程序如何自定义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将图片保存入mysql数据库失败的解决方法
2014/12/27 PHP
针对多用户实现头像上传功能PHP代码 适用于登陆页面制作
2016/08/17 PHP
在Mac OS下搭建LNMP开发环境的步骤详解
2017/03/10 PHP
PHP微信模板消息操作示例
2017/06/29 PHP
tp5(thinkPHP5)框架实现多数据库查询的方法
2019/01/10 PHP
跨域表单提交状态的变相判断代码
2009/11/12 Javascript
jQuery 源码分析笔记(2) 变量列表
2011/05/28 Javascript
js实现上传图片之上传前预览图片
2013/03/25 Javascript
jquery ajax 调用失败的原因示例介绍
2013/09/27 Javascript
一个js控制的导航菜单实例代码
2013/12/03 Javascript
ie7+背景透明文字不透明超级简单的实现方法
2014/01/17 Javascript
JavaScript jQuery 中定义数组与操作及jquery数组操作
2015/12/18 Javascript
javascript中FOREACH数组方法使用示例
2016/03/01 Javascript
JavaScript中将数组进行合并的基本方法讲解
2016/03/07 Javascript
BootStrap制作导航条实例代码
2016/05/06 Javascript
jquery计算出left和top,让一个div水平垂直居中的简单实例
2016/07/13 Javascript
从零学习node.js之文件操作(三)
2017/02/21 Javascript
js正则表达式验证密码强度【推荐】
2017/03/03 Javascript
BootStrap Fileinput插件和Bootstrap table表格插件相结合实现文件上传、预览、提交的导入Excel数据操作步骤
2017/08/07 Javascript
详解javascript 正则表达式之分组与前瞻匹配
2018/05/30 Javascript
Vue实现底部侧边工具栏的实例代码
2018/09/03 Javascript
vue.js的状态管理vuex中store的使用详解
2019/11/08 Javascript
Python中用psycopg2模块操作PostgreSQL方法
2017/11/28 Python
Python读取英文文件并记录每个单词出现次数后降序输出示例
2018/06/28 Python
使用Python获取网段IP个数以及地址清单的方法
2018/11/01 Python
Django项目中添加ldap登陆认证功能的实现
2019/04/04 Python
python下载卫星云图合成gif的方法示例
2020/02/18 Python
使用wxpy实现自动发送微信消息功能
2020/02/28 Python
Python常用模块函数代码汇总解析
2020/08/31 Python
采购员的工作职责
2013/12/26 职场文书
经典促销广告词大全
2014/03/19 职场文书
小学一年级数学教学计划
2015/01/20 职场文书
仰望星空观后感
2015/06/10 职场文书
嘉年华活动新闻稿
2015/07/17 职场文书
小学六年级毕业感言
2015/07/30 职场文书
python Polars库的使用简介
2021/04/21 Python