检查是否使用了视口 meta 标签

14

我有一个画布需要在浏览器窗口大小调整时重新调整大小,因此我有以下内容:

var resizeCanvas = function () {
    var ratio =  Math.max(window.devicePixelRatio || 1, 1);
    canvas.width = (canvas.offsetWidth || canvas.width) * ratio;
    canvas.height = (canvas.offsetHeight || canvas.height) * ratio;
    canvas.getContext('2d').scale(ratio, ratio);
}

window.addEventListener('resize', resizeCanvas);

在移动设备上滚动会触发调整大小事件,这对于其他方面都运行良好的软件来说是不可取的。

这是不希望看到的,因为调整画布的大小会清除其内容,这意味着当移动用户滚动时,画布总是被擦除。

有了这个答案的帮助,我想出了一种基于缓存宽度并进行双重检查的解决方案,但根据我的设计,我实际上只需要解决受到视口元标记影响的设备的问题:

<meta name="viewport" content="width=device-width, initial-scale=1">

有没有办法可以检查浏览器是否正在使用那个元标记?我在寻找类似于:

if(viewportMetaTagIsUsed){
    //For mobile browsers
    window.addEventListener("orientationchange", resizeCanvas);
} else {
    //For desktop browsers
    window.addEventListener('resize', resizeCanvas);
}

有没有可能绑定到touchmove事件并检测事件是否实际上是由滚动引起的?另外,我在我的Android设备上注意到的一件事是,当我到达页面的末尾和开头时,调整大小事件才会追加。另外,您可以使用此处的代码检测浏览器:https://dev59.com/WWgu5IYBdhLWcg3wWl4q - Mathieu de Lorimier
8个回答

8
据我所知,无法检测浏览器是否能够处理视口元标记。
以下是一些可供考虑的替代方案...

替代方案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');

这段浏览器嗅探代码是 一个名为isMobile的库 的代码。

备选方案2:window.orientation

测试window.orientation是否定义:

alert(typeof window.orientation !== 'undefined' ? 'Mobile' : 'Not mobile');


我有一台1024x768的笔记本电脑。 - Serge Seredenko
@SergeSeredenko:对于台式电脑而言,1024x768屏幕分辨率越来越少见了,但备选项#3显然是最不可靠的,因此我将其移除。 - John Slegers
window.orientation 不是被 window.screen.orientation 取代了吗?后者在桌面浏览器中也得到了支持。 - Mister Epic
@MisterEpic:第二种选择的关键在于window.orientation不被桌面浏览器支持。 - John Slegers
明白了,但您能确认它仅受到所有现有和未来的移动浏览器支持吗? - Mister Epic
1
请不要进行用户代理嗅探,当有一个使用略微不同的用户代理字符串发布的新手机时,这会导致您的应用程序出现问题。 - Shelvacu

3
理想情况下,您应该将移动设备和桌面设备视为相同,因为界限非常模糊。使用键盘支撑的平板电脑?带有触摸屏的笔记本电脑?唯一的区别就在于此时CPU的位置。
坚持您原来的做法:缓存宽度并检查是否更改。不要尝试确定设备是移动设备还是桌面设备,因为您最终会失败。

2

你尝试过以下方法吗:

var viewportMetaTag = document.querySelector('meta[name="viewport"]');
var viewportMetaTagIsUsed = viewportMetaTag && viewportMetaTag.hasAttribute('content') ? true : false;

MDN 上的文档:


3
这仅表示元标记是否存在,而在桌面和移动浏览器中都存在。只是移动浏览器会将其作为提示,将网页放大以占用设备的全部宽度。你的代码将始终返回true(附注:你不需要在结尾使用三元运算符)。 - Mister Epic
啊,是的,现在我明白你要找什么了。 - Viktor

2
您可以检查是否存在orientationchange事件,然后根据该事件分配函数。类似下面的代码:

您可以检查是否存在orientationchange事件,然后根据该事件分配函数。类似下面的代码

if("onorientationchange" in window) {
  //For mobile browsers
  window.addEventListener("orientationchange", resizeCanvas);
} else{
  //For desktop browsers
  window.addEventListener('resize', resizeCanvas);
}

以下代码段用于检测事件支持,引自下面的线程:

如何检测给定JavaScript事件的支持?


2

试试这个:

//mobile detection
    var isDevice = false;
    if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
        isDevice = true;
        // your code ...
    }

或者:

if ($('meta[name="viewport"]').size() > 0) {
      // your code ...
}

或者:

if ($('meta[name="viewport"]').attr('content').indexOf('device-width') - 1) {
      // your code ...
}

1
我认为你想要的不仅仅是检测视口标签的使用,而是确定你是否在移动浏览器中运行。
这个答案中,我们可以获取一个用于检测大多数移动浏览器的函数:
window.mobilecheck = function() {
    var 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;
}

然后你可以使用它来做你想做的事情:
if(window.mobilecheck()){
    //For mobile browsers
    window.addEventListener("orientationchange", resizeCanvas);
} else {
    //For desktop browsers
    window.addEventListener('resize', resizeCanvas);
}

哦,是的,那是一个选项,但我希望不必进行UA嗅探。 - Mister Epic

1
你可以通过js更改meta标签的内容(例如,将其设置为width=123)。现在,你必须在页面中有这样一个元素,它肯定会因此改变其大小(也许是div@width:100%)。之后,你恢复meta的原始值,但已经知道它是否对浏览器有任何意义。
如果你选择这种方法,应该将过程的结果保存到localStorage或cookie中,以便只需一次干扰页面。

0

试试这个:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=0.1">
<script>
    var width=$(window).width();
    $('meta[name=viewport]').attr('content','width=device-width, initial-scale=1');
    var newWidth=$(window).width();
    var viewportMetaTagIsUsed=width!=newWidth;
    alert(viewportMetaTagIsUsed?'using meta viewport':'not using meta viewport');
</script>

或者更加封装:

 function usesViewport() {
  var meta=$('meta[name=viewport]');
  var content=meta.attr('content');
  if (!meta.length) {
   meta=$('<meta name="viewport" content="width=device-width, initial-scale=1" />').appendTo('head');
   console.log(meta.parent());
  }
  $('meta[name=viewport]').attr('content','width=device-width, initial-scale=1');
  var width1=$(window).width();
  $('meta[name=viewport]').attr('content','width=device-width, initial-scale=0.1');
  var width2=$(window).width();
  if (content) {
   $('meta[name=viewport]').attr('content',content);
  } else {
   meta.remove();
  }
  var result=width1!=width2;
  return result;
 }
 $(function() {
  alert(usesViewport()?'Uses viewport':'Doesn\'t use viewport');
 });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

我不知道为什么它在这里不起作用,可能与脚本的沙盒有关,但是我已经复制并粘贴到维基百科的控制台中,例如,它可以工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接