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 相关文章推荐
js计算字符串长度包含的中文是utf8格式
Oct 15 Javascript
深入理解JavaScript是如何实现继承的
Dec 12 Javascript
js中switch case循环实例代码
Dec 30 Javascript
javascript解析xml实现省市县三级联动的方法
Jul 25 Javascript
jQuery实现仿百度首页滑动伸缩展开的添加服务效果代码
Sep 09 Javascript
JS遍历ul下的li点击弹出li的索引的实现方法
Sep 19 Javascript
JSON与js对象序列化实例详解
Mar 16 Javascript
微信小程序 下拉菜单的实现
Apr 06 Javascript
Node.js搭建WEB服务器的示例代码
Aug 15 Javascript
解决vue props 拿不到值的问题
Sep 11 Javascript
jquery多级树形下拉菜单的实例代码
Jul 09 jQuery
javascript网页随机点名实现过程解析
Oct 15 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 htmlentities和htmlspecialchars 的区别
2008/08/18 PHP
php使用for语句输出三角形的方法
2015/06/09 PHP
thinkphp5框架实现数据库读取的数据转换成json格式示例
2019/10/10 PHP
PHP cookie与session会话基本用法实例分析
2019/11/18 PHP
通用javascript脚本函数库 方便开发
2009/10/13 Javascript
javascript setTimeout和setInterval 的区别
2009/12/08 Javascript
jQuery遍历对象、数组、集合实例
2014/11/08 Javascript
jQuery中offsetParent()方法用法实例
2015/01/19 Javascript
JavaScript函数使用的基本教程
2015/06/04 Javascript
jquery显示loading图片直到网页加载完成的方法
2015/06/25 Javascript
纯javascript模仿微信打飞机小游戏
2015/08/20 Javascript
原生js仿jquery一些常用方法(必看篇)
2016/09/20 Javascript
Html中 IFrame的用法及注意点
2016/12/22 Javascript
Vue 项目部署到服务器的问题解决方法
2017/12/05 Javascript
Angular实现可删除并计算总金额的购物车功能示例
2017/12/26 Javascript
JavaScript中var、let、const区别浅析
2018/06/24 Javascript
jQuery插件simplePagination的使用方法示例
2020/04/28 jQuery
利用一个简单的例子窥探CPython内核的运行机制
2015/03/30 Python
打包发布Python模块的方法详解
2016/09/18 Python
python访问抓取网页常用命令总结
2017/04/11 Python
浅谈Python 的枚举 Enum
2017/06/12 Python
python使用matplotlib模块绘制多条折线图、散点图
2020/04/26 Python
Python实现时间序列可视化的方法
2019/08/06 Python
python异步编程 使用yield from过程解析
2019/09/25 Python
python报错: 'list' object has no attribute 'shape'的解决
2020/07/15 Python
Pyside2中嵌入Matplotlib的绘图的实现
2021/02/22 Python
一个不错的HTML5 Canvas多层点击事件监听实例
2014/04/29 HTML / CSS
HTML5 canvas基本绘图之绘制曲线
2016/06/27 HTML / CSS
美国新蛋IT数码商城:Newegg.com
2016/07/21 全球购物
测试时代收集的软件测试面试题
2013/09/25 面试题
《我不是最弱小的》教学反思
2014/02/23 职场文书
《山谷中的谜底》教学反思
2014/04/26 职场文书
公司市场部岗位职责
2015/04/15 职场文书
中秋节祝酒词
2015/08/12 职场文书
浅谈Python基础之列表那些事儿
2021/05/11 Python
Python实现的扫码工具居然这么好用!
2021/06/07 Python