我有一个画布,需要在调整浏览器窗口大小时调整大小,所以我有以下内容:
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);
这非常有效,除了在移动设备上滚动会触发 resize 事件。
这是不希望的,因为调整画布大小会清除其内容,这意味着当移动用户滚动时,画布始终会被擦除。
感谢这个答案我想出了一个基于缓存宽度并仔细检查的解决方案,但根据我的设计,我实际上只需要解决受我的视口元标记影响的设备的问题:
<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);
}
据我所知,无法检测浏览器是否能够处理视口元标记。
以下是一些可供考虑的替代方案...
!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 的库的代码。
测试是
window.orientation
的定义:
alert(typeof window.orientation !== 'undefined' ? 'Mobile' : 'Not mobile');
理想情况下,您应该将移动设备和台式机视为相同,因为界限非常模糊。带键盘支撑的平板电脑?带触摸屏的笔记本电脑?唯一的区别是 cpu 此时所在的位置。
坚持你正在做的事情:缓存宽度并检查它是否发生变化。不要尝试确定设备是移动设备还是桌面设备,因为您有时会失败。
你尝试过吗:
var viewportMetaTag = document.querySelector('meta[name="viewport"]');
var viewportMetaTagIsUsed = viewportMetaTag && viewportMetaTag.hasAttribute('content') ? true : false;
MDN 上的文档:
您可以检查orientationchange事件是否存在,并根据该事件分配功能。像下面的代码
if("onorientationchange" in window) {
//For mobile browsers
window.addEventListener("orientationchange", resizeCanvas);
} else{
//For desktop browsers
window.addEventListener('resize', resizeCanvas);
}
检测事件支持的代码片段取自下面的线程
试试这个:
//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 ...
}
我认为你想要的不一定是检测视口标签的使用,而是检测你是否在移动浏览器中运行。
从这个答案我们可以找到一个检测大多数移动浏览器的功能:
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);
}
您可以通过js更改meta标签的内容(例如将其设置为
width=123
)。现在,您的页面中必须有这样一个元素,它肯定会因此改变其大小(也许是div@width:100%
?)。之后,您恢复元的原始值,但已经知道它对浏览器是否意味着什么。
如果你这样做,过程的结果应该保存到localStorage或cookie,这样你就只会弄乱页面一次。
试试这个:
<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>
我不知道为什么它在这里不起作用,可能与脚本的沙箱有关,但是,我仍然将其复制并粘贴到维基百科的控制台中,并且它可以工作。
您可以通过重新配置视口来检查视口元标记的有效性。 请参阅下面的代码,该代码已在 iOS Safari、Android Chrome、Android Firefox 上测试。
function checkIfViewportMetaEffective() {
return new Promise((resolve, reject) => {
let meta = document.querySelector('meta[name="viewport"]');
if (!meta) {
reject(new Error('No viewport meta tag found'));
return;
}
let content = meta.content;
let root = document.documentElement;
let tempWidth = root.clientWidth + 3;
let resolved = false;
let isApproxmate = (a, b, epsilon = 1) => {
return a > b - epsilon && a < b + epsilon;
};
let resizeHandler = (e) => {
resolved = true;
visualViewport.removeEventListener('resize', resizeHandler);
console.log(root.clientWidth, tempWidth);
resolve(isApproxmate(root.clientWidth, tempWidth, 1));
// reset viewport and trigger repaint again
meta.content = content;
div.remove();
};
visualViewport.addEventListener('resize', resizeHandler);
setTimeout(() => { if (!resolved) resizeHandler(); }, 50);
// reconfigure viewport and trigger repaint
meta.content = content.replace('device-width', tempWidth);
let div = document.body.appendChild(document.createElement('div'));
});
}
queueMicrotask(async () => {
let text = 'is viewport meta effective? ' + await checkIfViewportMetaEffective();
console.log(text);
});