「我正在参与掘金创作者训练营第4期,点击了解活动详情,一起学习吧!」
前言
距离上次发布文章还是有一段时间了,最近上班有点迷不在状态,做什么事都提不起兴趣,一时不知道到底如何抉择了,大概是外界和心态的影响吧。
纵使万般不愿,但今天还是要提起兴趣来写一篇文章,毕竟报名了掘金创作训练营,也听了大佬的直播讲解,所以是骡子是马写出来溜溜
,让大家来瞅瞅有没有得到大佬的精髓。老话说得好:实践是检验真理的唯一标准
,更何况写文章这事并不是一日就能成,还是要多写才能得心应手,所以后面还是要多产出点优质文章来用其共勉。
今天聊聊如何让项目只支持谷歌浏览器进行访问查看,其它浏览器访问时进行拦截并提示需下载谷歌浏览器?
需求背景
先说背景,为什么需要做这样的需求肯定有原因的?原因就是由于公司人鱼混杂,计算机的相关知识参差不齐,一些小白用户在明确建议其使用谷歌浏览器访问的前提下,还是下载山寨谷歌浏览器
或者使用低版本的IE浏览器
进行访问,最后控诉程序存在bug,无法正常使用;对此,为了解决该小白群体的客服问题和避免时间过多的浪费在此类问题上,我们领导决定"一刀切",那就是不使用谷歌浏览器
访问的用户一律进行拦截且不可进入页面查看,需下载谷歌浏览器才能正常访问平台页面。
由上就引出了我们要实现的需求,那就是在项目中加入判断浏览器的代码并跳转到提示页面提示下载谷歌浏览器
。老规矩上图理解需求,下图就是已实现的效果图:
思考
我想这个需求一抛出来,肯定有小伙伴要问这样"一刀切"是否合适?为什么不去做兼容?这些问题肯定我们也有过思考,首先说说兼容,现在的用户基本很少使用IE浏览器
,不能说没有只能说很少,那既然用户群体很少我们就没有必要尽善尽美的满足所有浏览器,我们只要做到能满足95%
的用户使用的主流浏览器没有问题就已足矣;做兼容会消耗我们的很多时间而且还有可能做不完全,所以我们选择舍弃那5%
的用户,通过其它方式告诉他选择主流浏览器使用就可节约做兼容的时间,这样的性价比才是最好的。故没有为了少数用户群体去做兼容,也就有了"一刀切"的处理方式;然后说"一刀切"的方式在程序开发中的问题,在程序开发中我们肯定会兼顾所有的群体,竭尽所能的让用户体验达到极致,但由于公司现行的规则和所处的开发环境,开发时间不足以让我们做到完美,故也就有此种处理行为。
尽管有理有据,但是作为有代码洁癖的开发来说,这不是一种完美的解决方式,但是这也不失为一种完美的解决方式,故就在于如何去理解当下的方式是否妥当之问,一切的一切都是为了解决问题而解决问题,至于其中道道肯定有一定的缘由存在。
书归正传,以上需求是否有难度,难度几何呢?又有何思考呢?请看下面所举:
- 在项目哪里进行判断?出于怎样的考虑?
- 判断浏览器用何API?
- 如何对url进行编码和解码?
- 怎么让代码自己执行判断?
开发
好了,书接上文。现在就来解决上述思考。
问题一 ★★★☆☆
要回答问题一,那就先说说我们的平台:首先我们的主平台是使用Vue
技术栈进行开发的,主平台里面的有些页面是属于另一个使用React
技术栈开发的平台(这里把它称为平台2吧,后面好理解),即一个平台包含两种技术开发的页面,但要解决的问题主要是主平台这个壳子的入口,即使用Vue
技术栈开发的主平台,所以下面的叙述可能含有Vue
相关术语。
好,平台的构造了解了,那就说解决之法。
我们首先考虑是将判断的代码写进主页面的Created
生命周期里面去判断的,但是这样会导致页面先进入平台设置的主页面之后再跳转到提醒页面,这样的体验有点不友好;然后我们想在全局守卫beforeEach
处进行判断,但是又想到代码在此处处理会显得不是那么优雅,所以就没有选择这样的方式。那还有什么样的方式既优雅又能解决问题呢?那就是我们选择的最优方案,就是在index.html
页面增加逻辑代码进行判断,然后重定向到提醒页面进行提醒,这样的好处就是输入网址解析之后进入页面就直接走判断逻辑,而没有进入项目的其它页面,使得体验相较更好。
如何去做?这里展示的是文件目录和使用的截图,后续的问题思考会逐一解答解决。
问题二 ★☆☆☆☆
根据MDN前端文档介绍:
Navigator:接口表示用户代理的状态和标识。
它允许脚本查询它和注册自己进行一些活动。
可以使用只读的属性检索navigator对象。
而JS判断浏览器类型的核心方法就是使用:navigator.userAgent
,返回当前浏览器的用户代理(user agent)字符串。
我们在谷歌浏览器
控制台通过调用Navigator
对象的相关属性可以看到浏览器的一些相关信息,如下图所示:
根据MDN介绍可知Navigator
相关属性如下表所示:
属性 | 描述 |
---|---|
appCodeName | 返回浏览器的代码名。 |
appMinorVersion | 返回浏览器的次级版本。 |
appName | 返回浏览器的名称。 |
appVersion | 返回浏览器的平台和版本信息。 |
browserLanguage | 返回当前浏览器的语言。 |
cookieEnabled | 返回指明浏览器中是否启用 cookie 的布尔值。 |
cpuClass | 返回浏览器系统的 CPU 等级。 |
onLine | 返回指明系统是否处于脱机模式的布尔值。 |
platform | 返回运行浏览器的操作系统平台。 |
systemLanguage | 返回 OS 使用的默认语言。 |
userAgent | 返回由客户机发送服务器的 user-agent 头部的值。 |
userLanguage | 返回 OS 的自然语言设置。 |
通过上表我们可以获知浏览器的名称、版本信息、CPU等级等信息;如果在需求不是特别严格的情况下,需要根据浏览器做判断,其实使用navigator.userAgent这
这个API
就足够了,至于其它API
根据自身需求自行选取就可。
问题三 ★★★☆☆
回答问题三,那就要先讲讲为什么要对url
进行编码,才能讲后面的如何编码?
在HTTP协议中参数组件的传输是key=value
键值对的形式,若要传输多个参数需要使用&
符号进行分隔。如http://www.xxx.com/index.html?name=zhangsan&age=18&sex=1
,这样服务器在收到这种字符串的时候,会用&
符号分割出每一个参数,然后用=
来分隔出参数值。
而如果用户传递的参数中包含了&
或者=
这样的特殊字符时,会是怎样的?如http://www.xxx.com/index.html?name1=zhang&san=1
,本意是传递name1=zhang&san=1
,但是服务器就会解析为name1=zhang
和san=1
,这样就产生了歧义。
所以为了解决上述问题,我们就需要对url
进行编码。好了,原因我们知道了,下面来说如何编码和解码?
JS中提供3个函数对url
进行编码和解码,分别是escape/unescape
,encodeURI/decodeURI
,encodeURIComponent/decodeURIComponent
。
escape/unescape方法:
scape方法返回一个包含charstring内容的字符串值(Unicode格式)。所有空格、标点、重音符号以及任何其他非 ASCII字符都用%xx编码替换,其中xx等于表示该字符的十六进制数;
unescape方法是从用escape方法编码的String对象中返回已解码的字符串。
不可编码字符: @ * / +
encodeURI/decodeURI方法:
encodeURI方法返回一个已编码的url。如果将编码结果传递给decodeURI,则将返回初始的字符串。encodeURI不对下列字符进行编码:“:”、“/”、“;”和“?”。请使用encodeURIComponent对这些字符进行编码;
decodeURI方法是从用encodeURI方法编码的String对象中返回已解码的字符串。
不可编码字符:! @ # $ & * ( ) = : / ; ? +
encodeURIComponent/decodeURIComponent方法:
encodeURIComponent方法返回一个已编码的url。如果将编码结果传递给decodeURIComponent,则将返回初始的字符串。因为encodeURIComponent方法将对所有字符编码;
decodeURIComponent方法是从用encodeURIComponent方法编码的String对象中返回已解码的字符串。
不可编码字符:! * ( )
注:若要对Url编码,escape方法是针对字符串使用的,不适用于Url;对Url编码使用encodeURI和encodeURIComponent方法,两者之中又由于encodeURIComponent编码范围更大,故推荐使用encodeURIComponent方法。
问题四 ★★☆☆☆
怎么让代码自动执行?那就引入自执行函数:即自执行函数是在函数内部执行函数本身。
怎么理解?示例如下:
function a() {
console.log('123');
}
a();
定义一个函数,如果要执行它就得调用它a()
;而自执行函数就是当它被定义出来就会自动执行,不需要调用。
(function a() {
console.log('123');
})();
或
(function a() {
console.log('123');
}());
好了,关于该需求引出的思考需要用到的解决办法和知识就介绍得差不多了,这样我们带着知识去理解后面贴出的实现代码就容易多了,请往下看→
完整代码
在static
文件夹下创建browserCheck
文件夹,接着在此文件夹下分别创建index.js
、index.html
、redirect.js
文件。
index.js
文件:
// 只兼容谷歌浏览器检查
(function () {
let agent = navigator.userAgent;
if (agent.indexOf('Chrome') === -1 || agent.indexOf('Edge') > -1) {
location.href = '/static/browserCheck/index.html?originUrl=' + encodeURIComponent(location.href);
}
})();
从代码可以看到,我们只做了兼容谷歌浏览器的检查,其中用到了navigator.userAgent
获取浏览器信息,使用encodeURIComponent
对url
参数进行编码,使用自执行函数让函数自动执行。然后在项目的index.html
文件中引入该文件。
<script src="/static/browserCheck/index.js"></script>
接下来是index.html
文件,用于展示提醒消息和提供谷歌浏览器
下载地址:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>首页(浏览器兼容性检查)</title>
<script src="/static/browserCheck/redirect.js"></script>
</head>
<body>
<style>
* {
margin: 0;
padding: 0;
}
body {
background: #EDF1F7;
}
.browser-check-box-wrap {
margin: 300px auto 0 auto;
width: 600px;
height: 500px;
}
.browser-check-box-wrap h2 {
font-size: 20px;
text-align: center;
}
.browser-check-download-box {
margin-top: 30px;
text-align: center;
}
.browser-check-download-box h3 {
font-size: 15px;
text-align: center;
}
.browser-check-download-box p {
margin-top: 20px;
}
.browser-check-download-box a {
display: inline-block;
width: 120px;
height: 40px;
line-height: 40px;
color: #fff;
background: #f60016;
border: 1px solid #f60016;
text-decoration: none;
border-radius: 2px;
}
.browser-check-download-box a:hover {
cursor: pointer;
background-color: #FF696B;
border-color: #FF696B;
}
</style>
<div class="browser-check-box-wrap">
<h2>为了您更好的体验,本网站现仅支持谷歌浏览器</h2>
<div class="browser-check-download-box">
<h3>谷歌浏览器 稳定版 64位专版</h3>
<p>
<img src="https://pc3.gtimg.com/softmgr/logo/48/21258_48_1450768968.png" alt="" />
</p>
<p>
<a href="https://dl.softmgr.qq.com/original/Browser/96.0.4664.45_chrome_installer-64.exe">点击下载</a>
</p>
</div>
</div>
</body>
</html>
redirect.js
文件:
(function () {
// 获取query参数
function getQueryParams() {
var params = {};
var href = location.href;
if (href.indexOf('?') === -1) {
return params;
}
var search = href.split('?').slice(-1)[0];
if (!search) {
return params;
}
var temp = search.split('&');
temp.forEach(v => {
if (!v) {
return;
}
var index = v.indexOf('=');
if (index > -1) {
params[v.substring(0, index)] = decodeURIComponent(v.substring(index + 1));
}
});
return params;
}
// 如果是谷歌浏览器,则直接重定向到来源页
var agent = navigator.userAgent;
console.log('agent', agent);
if (agent.indexOf('Chrome') > -1 && agent.indexOf('Edge') === -1) {
var url = '/';
var query = getQueryParams();
if (query && query.originUrl) {
url = query.originUrl;
}
location.href = url;
}
})();
可以看到我们在js文件中定义了一个获取url
参数的函数,然后再一次判断浏览器类型,若为谷歌浏览器,则直接重定向到来源页,从而达到上述产品需求效果。
下图展示的是浏览器为Edge和IE11浏览器上的信息结果,就会更清楚为何判断要加入代码agent.indexOf('Chrome')
进行判断,原因就是Edge的浏览器信息含有Chrome
字符。
至此,如何让项目只支持谷歌浏览器进行访问查看的需求的实现方法就聊完了,最后的实现效果请看需求背景的最后一张截图,效果和体验还是挺不错的。如果小伙伴们后续也有这样的需求,可以参考一下我的实现过程,希望可以帮助到各位掘友^_^
往期精彩文章
- 聊聊如何在React项目中使用Antd的Table组件实现Echarts的热力图效果?
- 如何在前端项目中引入外部字体并使用?
- 如何在React项目中使用高德地图插件并封装弹窗组件呢?
- 数据可视化-如何在React项目中使用Echarts插件并封装图表组件?
- 快来看看我是如何更改Antd中DatePicker周选择器默认设置的?
- 如何封装Vue水印组件和 React中如何使用水印组件?
- 最强富文本编辑器?TinyMCE系列文章【3】
- 最强富文本编辑器?TinyMCE系列文章【2】
- 最强富文本编辑器?TinyMCE系列文章【1】
- 在React项目中实现仿饿了么Checkbox多选按钮样式的效果组件
- 2022第一次更文:前端项目实战中的3种Progress进度条效果
- 2022年前端技术趋势:你不进来看看,怎么赚它一个小目标?
- 假如古代有程序员写总结,大概就是这样吧 | 2021年终总结
后语
伙伴们,如果觉得本文对你有些许帮助,点个👍或者➕个关注在走呗^_^ 。另外如果本文章有问题或有不理解的部分,欢迎大家在评论区评论指出,我们一起讨论共勉。