![](/img/trans.png)
[英]What is the best way to detect retina support on a device using JavaScript?
[英]What's the best way to detect a 'touch screen' device using JavaScript?
我編寫了一個可在桌面和移動設備上使用的 jQuery 插件。 我想知道是否有一種方法可以使用 JavaScript 來檢測設備是否具有觸摸屏功能。 我正在使用 jquery-mobile.js 來檢測觸摸屏事件,它適用於 iOS、Android 等,但我還想根據用戶的設備是否有觸摸屏來編寫條件語句。
那可能嗎?
2021 年更新
要查看舊答案:檢查歷史記錄。 我決定從頭開始,因為在帖子中保留歷史時它已經失控了。
我最初的回答說,使用與 Modernizr 相同的功能可能是個好主意,但這不再有效,因為他們刪除了此 PR 上的“touchevents”測試: https : //github.com/Modernizr/Modernizr /pull/2432因為它是一個令人困惑的主題。
話雖如此,這應該是一種檢測瀏覽器是否具有“觸摸功能”的相當不錯的方法:
function isTouchDevice() {
return (('ontouchstart' in window) ||
(navigator.maxTouchPoints > 0) ||
(navigator.msMaxTouchPoints > 0));
}
但是對於更高級的用例,比我寫過的關於這個主題的人更聰明,我建議閱讀這些文章:
由於 Modernizr 在 Windows Phone 8/WinRT 上沒有檢測到 IE10,一個簡單的跨瀏覽器解決方案是:
var supportsTouch = 'ontouchstart' in window || navigator.msMaxTouchPoints;
您只需要檢查一次,因為設備不會突然支持或不支持觸摸,所以只需將其存儲在一個變量中,這樣您就可以更有效地多次使用它。
由於引入了交互媒體功能,您可以簡單地執行以下操作:
if(window.matchMedia("(pointer: coarse)").matches) {
// touchscreen
}
https://www.w3.org/TR/mediaqueries-4/#descdef-media-any-pointer
更新(由於評論):上述解決方案是檢測“粗指針”(通常是觸摸屏)是否是主要輸入設備。 如果您想檢測帶有鼠標的設備是否也有觸摸屏,您可以使用any-pointer: coarse
代替。
有關更多信息,請查看此處: 檢測瀏覽器沒有鼠標並且僅觸摸
使用上面的所有評論,我組裝了以下代碼,以滿足我的需要:
var isTouch = (('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0));
我已經在 iPad、Android(瀏覽器和 Chrome)、Blackberry Playbook、iPhone 4s、Windows Phone 8、IE 10、IE 8、IE 10(帶觸摸屏的 Windows 8)、Opera、Chrome 和 Firefox 上對此進行了測試。
它目前在 Windows Phone 7 上失敗,我還沒有找到適用於該瀏覽器的解決方案。
希望有人覺得這很有用。
我喜歡這個:
function isTouchDevice(){
return typeof window.ontouchstart !== 'undefined';
}
alert(isTouchDevice());
如果您使用Modernizr ,則使用前面提到的Modernizr.touch
非常容易。
但是,為了安全起見,我更喜歡結合使用Modernizr.touch
和用戶代理測試。
var deviceAgent = navigator.userAgent.toLowerCase();
var isTouchDevice = Modernizr.touch ||
(deviceAgent.match(/(iphone|ipod|ipad)/) ||
deviceAgent.match(/(android)/) ||
deviceAgent.match(/(iemobile)/) ||
deviceAgent.match(/iphone/i) ||
deviceAgent.match(/ipad/i) ||
deviceAgent.match(/ipod/i) ||
deviceAgent.match(/blackberry/i) ||
deviceAgent.match(/bada/i));
if (isTouchDevice) {
//Do something touchy
} else {
//Can't touch this
}
如果你不使用 Modernizr,你可以簡單地將上面的Modernizr.touch
函數替換為('ontouchstart' in document.documentElement)
另請注意,測試用戶代理iemobile
將為您提供比Windows Phone
更廣泛的檢測到的 Microsoft 移動設備。
我們嘗試了 Modernizr 實現,但檢測觸摸事件不再一致(IE 10 在 Windows 桌面上有觸摸事件,IE 11 可以工作,因為已經刪除了觸摸事件並添加了指針 api)。
所以我們決定將網站優化為觸摸網站,只要我們不知道用戶有什么輸入類型。 這比任何其他解決方案都更可靠。
我們的研究表明,大多數桌面用戶在點擊之前會用鼠標在屏幕上移動,因此我們可以檢測到他們並在他們能夠點擊或懸停任何東西之前改變行為。
這是我們代碼的簡化版本:
var isTouch = true;
window.addEventListener('mousemove', function mouseMoveDetector() {
isTouch = false;
window.removeEventListener('mousemove', mouseMoveDetector);
});
有什么比檢查他們是否有觸摸屏更好的方法是檢查他們是否正在使用它,而且這更容易檢查。
if (window.addEventListener) {
var once = false;
window.addEventListener('touchstart', function(){
if (!once) {
once = true;
// Do what you need for touch-screens only
}
});
}
我是這樣實現的;
function isTouchDevice(){
return true == ("ontouchstart" in window || window.DocumentTouch && document instanceof DocumentTouch);
}
if(isTouchDevice()===true) {
alert('Touch Device'); //your logic for touch device
}
else {
alert('Not a Touch Device'); //your logic for non touch device
}
即使在 Windows Surface 平板電腦上也能很好地工作!!!
function detectTouchSupport {
msGesture = window.navigator && window.navigator.msPointerEnabled && window.MSGesture,
touchSupport = (( "ontouchstart" in window ) || msGesture || window.DocumentTouch && document instanceof DocumentTouch);
if(touchSupport) {
$("html").addClass("ci_touch");
}
else {
$("html").addClass("ci_no_touch");
}
}
嘗試檢測觸摸的最大“問題”是在支持觸摸和觸控板/鼠標的混合設備上。 即使您能夠正確檢測用戶的設備是否支持觸摸,您真正需要做的是檢測用戶當前使用的輸入設備。 此處詳細記錄了此挑戰和可能的解決方案。
基本上確定用戶是觸摸屏幕還是使用鼠標/觸控板的方法是在頁面上同時注冊touchstart
和mouseover
事件:
document.addEventListener('touchstart', functionref, false) // on user tap, "touchstart" fires first
document.addEventListener('mouseover', functionref, false) // followed by mouse event, ie: "mouseover"
觸摸操作將觸發這兩個事件,盡管前者 ( touchstart
) 在大多數設備上始終是第一個。 因此,依靠這個可預測的事件序列,您可以創建一種機制,動態地向文檔根添加或刪除can-touch
類,以反映用戶此時在文檔上的當前輸入類型:
;(function(){
var isTouch = false //var to indicate current input type (is touch versus no touch)
var isTouchTimer
var curRootClass = '' //var indicating current document root class ("can-touch" or "")
function addtouchclass(e){
clearTimeout(isTouchTimer)
isTouch = true
if (curRootClass != 'can-touch'){ //add "can-touch' class if it's not already present
curRootClass = 'can-touch'
document.documentElement.classList.add(curRootClass)
}
isTouchTimer = setTimeout(function(){isTouch = false}, 500) //maintain "istouch" state for 500ms so removetouchclass doesn't get fired immediately following a touch event
}
function removetouchclass(e){
if (!isTouch && curRootClass == 'can-touch'){ //remove 'can-touch' class if not triggered by a touch event and class is present
isTouch = false
curRootClass = ''
document.documentElement.classList.remove('can-touch')
}
}
document.addEventListener('touchstart', addtouchclass, false) //this event only gets called when input type is touch
document.addEventListener('mouseover', removetouchclass, false) //this event gets called when input type is everything from touch to mouse/ trackpad
})();
更多細節在這里。
實際上,我研究了這個問題並考慮了所有情況。 因為這也是我項目中的一個大問題。 所以我達到了以下功能,它適用於所有設備上所有瀏覽器的所有版本:
const isTouchDevice = () => {
const prefixes = ['', '-webkit-', '-moz-', '-o-', '-ms-', ''];
const mq = query => window.matchMedia(query).matches;
if (
'ontouchstart' in window ||
(window.DocumentTouch && document instanceof DocumentTouch)
) {
return true;
}
return mq(['(', prefixes.join('touch-enabled),('), 'heartz', ')'].join(''));
};
提示:當然, isTouchDevice
只返回boolean
值。
我使用上面的代碼片段來檢測是否觸摸,所以我的fancybox iframe 會顯示在台式機上而不是觸摸上。 我注意到當單獨使用 blmstr 的代碼時,適用於 Android 4.0 的 Opera Mini 仍然注冊為非觸摸設備。 (有誰知道為什么?)
我最終使用了:
<script>
$(document).ready(function() {
var ua = navigator.userAgent;
function is_touch_device() {
try {
document.createEvent("TouchEvent");
return true;
} catch (e) {
return false;
}
}
if ((is_touch_device()) || ua.match(/(iPhone|iPod|iPad)/)
|| ua.match(/BlackBerry/) || ua.match(/Android/)) {
// Touch browser
} else {
// Lightbox code
}
});
</script>
我會避免使用屏幕寬度來確定設備是否為觸摸設備。 有比 699 像素大得多的觸摸屏,想想 Windows 8。 Navigatior.userAgent 可能很好地覆蓋假陽性。
我建議在 Modernizr 上查看這個問題。
您是要測試設備是否支持觸摸事件或者是觸摸設備。 不幸的是,這不是一回事。
其中許多工作,但要么需要 jQuery,要么 javascript linters 抱怨語法。 考慮到您最初的問題要求使用“JavaScript”(不是 jQuery,不是 Modernizr)方法來解決這個問題,這里有一個每次都有效的簡單函數。 它也是盡可能少的。
function isTouchDevice() {
return !!window.ontouchstart;
}
console.log(isTouchDevice());
我要提到的最后一個好處是,此代碼與框架和設備無關。 享受!
不,這不可能。 給出的優秀答案只是部分的,因為任何給定的方法都會產生誤報和漏報。 由於操作系統 API,即使是瀏覽器也不總是知道是否存在觸摸屏,而且事實可能會在瀏覽器會話期間發生變化,尤其是 KVM 類型的安排。
請參閱這篇優秀文章中的更多詳細信息:
http://www.stucox.com/blog/you-cant-detect-a-touchscreen/
這篇文章建議您重新考慮讓您想要檢測觸摸屏的假設,它們可能是錯誤的。 (我檢查了我自己的應用程序,我的假設確實是錯誤的!)
文章總結道:
對於布局,假設每個人都有一個觸摸屏。 與觸摸用戶使用小型 UI 控件相比,鼠標用戶可以更輕松地使用大型 UI 控件。 懸停狀態也是如此。
對於事件和交互,假設任何人都可能擁有觸摸屏。 一起實現鍵盤、鼠標和觸摸交互,確保沒有相互阻塞。
看看這篇文章,它提供了一個非常好的代碼片段,用於在檢測到觸摸設備時要做什么或在調用 touchstart 事件時要做什么:
$(function(){
if(window.Touch) {
touch_detect.auto_detected();
} else {
document.ontouchstart = touch_detect.surface;
}
}); // End loaded jQuery
var touch_detect = {
auto_detected: function(event){
/* add everything you want to do onLoad here (eg. activating hover controls) */
alert('this was auto detected');
activateTouchArea();
},
surface: function(event){
/* add everything you want to do ontouchstart here (eg. drag & drop) - you can fire this in both places */
alert('this was detected by touching');
activateTouchArea();
}
}; // touch_detect
function activateTouchArea(){
/* make sure our screen doesn't scroll when we move the "touchable area" */
var element = document.getElementById('element_id');
element.addEventListener("touchstart", touchStart, false);
}
function touchStart(event) {
/* modularize preventing the default behavior so we can use it again */
event.preventDefault();
}
看起來 Chrome 24 現在支持觸摸事件,可能適用於 Windows 8。所以這里發布的代碼不再有效。 我現在沒有嘗試檢測瀏覽器是否支持觸摸,而是同時綁定觸摸和點擊事件,並確保只調用一個:
myCustomBind = function(controlName, callback) {
$(controlName).bind('touchend click', function(e) {
e.stopPropagation();
e.preventDefault();
callback.call();
});
};
然后調用它:
myCustomBind('#mnuRealtime', function () { ... });
希望這有幫助!
支持除桌面版 Firefox 之外的所有瀏覽器始終是正確的,因為桌面版 Firefox 支持開發人員的響應式設計,即使您單擊觸摸按鈕與否!
我希望 Mozilla 會在下一個版本中解決這個問題。
我正在使用 Firefox 28 桌面。
function isTouch()
{
return !!("ontouchstart" in window) || !!(navigator.msMaxTouchPoints);
}
jQuery v1.11.3
提供的答案中有很多很好的信息。 但是,最近我花了很多時間試圖將所有內容真正結合在一起,形成一個可行的解決方案,以完成兩件事:
除了這篇文章和使用 Javascript 檢測觸摸屏設備之外,我發現 Patrick Lauke 的這篇文章非常有幫助: https ://hacks.mozilla.org/2013/04/detecting-touch-its-the-why-not-the-how /
這是代碼...
$(document).ready(function() {
//The page is "ready" and the document can be manipulated.
if (('ontouchstart' in window) || (navigator.maxTouchPoints > 0) || (navigator.msMaxTouchPoints > 0))
{
//If the device is a touch capable device, then...
$(document).on("touchstart", "a", function() {
//Do something on tap.
});
}
else
{
null;
}
});
重要! *.on( events [, selector ] [, data ], handler )
方法需要有一個選擇器,通常是一個元素,可以處理“touchstart”事件,或與觸摸相關的任何其他類似事件。 在這種情況下,它是超鏈接元素“a”。
現在,您不需要在 JavaScript 中處理常規鼠標單擊,因為您可以使用 CSS 來處理這些事件,使用超鏈接“a”元素的選擇器,如下所示:
/* unvisited link */
a:link
{
}
/* visited link */
a:visited
{
}
/* mouse over link */
a:hover
{
}
/* selected link */
a:active
{
}
注意:還有其他選擇器......
由於混合設備使用觸摸和鼠標輸入的組合,您需要能夠動態更改狀態/變量,如果用戶是觸摸用戶,則控制一段代碼是否應該運行。
觸摸設備也會在點擊時觸發mousemove
。
touchstart
事件,然后將其設置為 true。在 Safari iOS 和 Chrome for Android 上測試。
注意:對 MS Surface 等的指針事件不是 100% 確定。
const supportsTouch = 'ontouchstart' in window;
let isUsingTouch = false;
// `touchstart`, `pointerdown`
const touchHandler = () => {
isUsingTouch = true;
document.addEventListener('mousemove', mousemoveHandler);
};
// use a simple closure to store previous time as internal state
const mousemoveHandler = (() => {
let time;
return () => {
const now = performance.now();
if (now - time < 20) {
isUsingTouch = false;
document.removeEventListener('mousemove', mousemoveHandler);
}
time = now;
}
})();
// add listeners
if (supportsTouch) {
document.addEventListener('touchstart', touchHandler);
} else if (navigator.maxTouchPoints || navigator.msMaxTouchPoints) {
document.addEventListener('pointerdown', touchHandler);
}
我認為最好的方法是:
var isTouchDevice =
(('ontouchstart' in window) ||
(navigator.maxTouchPoints > 0) ||
(navigator.msMaxTouchPoints > 0));
if(!isTouchDevice){
/* Code for touch device /*
}else{
/* Code for non touch device */
}
對,所以關於檢測觸摸/非觸摸設備存在巨大的爭論。 窗口平板電腦的數量和平板電腦的大小正在增加,這給我們的 Web 開發人員帶來了另一組麻煩。
我已經使用並測試了blmstr 的菜單答案。 菜單是這樣工作的:當頁面加載時,腳本檢測這是觸摸設備還是非觸摸設備。 基於此,菜單可以在懸停(非觸摸)或單擊/點擊(觸摸)時工作。
在大多數情況下,blmstr 的腳本似乎工作得很好(特別是 2018 年的那個)。 但是仍然有一種設備會被檢測為觸摸,反之亦然。
出於這個原因,我做了一些挖掘,感謝這篇文章,我將 blmstr 的第 4 個腳本中的幾行替換為:
function is_touch_device4() { if ("ontouchstart" in window) return true; if (window.DocumentTouch && document instanceof DocumentTouch) return true; return window.matchMedia( "(pointer: coarse)" ).matches; } alert('Is touch device: '+is_touch_device4()); console.log('Is touch device: '+is_touch_device4());
由於鎖定,用於測試此設備的觸摸設備供應有限,但到目前為止,上述方法效果很好。
如果任何擁有桌面觸摸設備(例如 Surface 平板電腦)的人都可以確認腳本是否正常工作,我會很感激。
現在就支持指針而言:似乎支持粗略的媒體查詢。 我保留了上面的行,因為我(出於某種原因)在移動 Firefox 上遇到了問題,但是媒體查詢上面的行可以解決問題。
謝謝
您可以安裝 Modernizer 並使用簡單的觸摸事件。 這非常有效,適用於我測試過的所有設備,包括 Windows 表面!
我創建了一個jsFiddle
function isTouchDevice(){
if(Modernizr.hasEvent('touchstart') || navigator.userAgent.search(/Touch/i) != -1){
alert("is touch");
return true;
}else{
alert("is not touch");
return false;
}
}
var isTouchScreen = 'createTouch' in document;
或
var isTouchScreen = 'createTouch' in document || screen.width <= 699 ||
ua.match(/(iPhone|iPod|iPad)/) || ua.match(/BlackBerry/) ||
ua.match(/Android/);
我想會是一個更徹底的檢查。
我使用:
if(jQuery.support.touch){
alert('Touch enabled');
}
在 jQuery 移動 1.0.1 中
關於如何在 Javascript 中檢測頁面是否顯示在觸摸屏設備上的不同選項,我也遇到了很多困難。 IMO,截至目前,不存在真正的選項來正確檢測該選項。 瀏覽器要么報告台式機上的觸摸事件(因為操作系統可能已准備好觸摸),要么某些解決方案不適用於所有移動設備。
最后,我意識到我從一開始就采用了錯誤的方法:如果我的頁面在觸摸設備和非觸摸設備上看起來相似,我可能根本不必擔心檢測屬性:我的場景是停用觸摸設備上按鈕上的工具提示,因為它們會導致雙擊,我希望單擊一下即可激活按鈕。
我的解決方案是重構視圖,以便在按鈕上不需要工具提示,最后我不需要使用都有其缺點的方法從 Javascript 檢測觸摸設備。
實際的答案似乎是考慮上下文的答案:
1)公共站點(無需登錄)
編寫 UI 以同時使用這兩個選項。
2) 登錄網站
捕獲登錄表單上是否發生鼠標移動,並將其保存到隱藏輸入中。 該值與登錄憑據一起傳遞並添加到用戶的session 中,因此它可以在會話期間使用。
僅添加到登錄頁面的 Jquery:
$('#istouch').val(1); // <-- value will be submitted with login form
if (window.addEventListener) {
window.addEventListener('mousemove', function mouseMoveListener(){
// Update hidden input value to false, and stop listening
$('#istouch').val(0);
window.removeEventListener('mousemove', mouseMoveListener);
});
}
(+1 @Dave Burt 和+1 @Martin Lantzsch 在他們的回答中)
jQuery support
對象的范圍:
jQuery.support.touch = 'ontouchend' in document;
現在你可以在任何地方檢查它,像這樣:
if( jQuery.support.touch )
// do touch stuff
到目前為止,這對我來說似乎還不錯:
//Checks if a touch screen
is_touch_screen = 'ontouchstart' in document.documentElement;
if (is_touch_screen) {
// Do something if a touch screen
}
else {
// Not a touch screen (i.e. desktop)
}
快速注意那些可能想寫windows.ontouchstart window.ontouchstart !== undefined
- >請使用micnic的答案,因為undefined
不是JavaScript中的關鍵字。 如果開發寫了類似的東西:
undefined = window.ontouchstart;
開發人員可以根據需要制作任何未定義的內容,您也可以檢查window.ontouchstart = myNonExistingWord;
對那些給出這個答案的人不要不尊重:我很確定我也在我的代碼中寫了這個;)
當連接了鼠標時,可以假定用戶以相當高的命中率(實際上可以說是100%)在頁面准備好之后用戶至少將鼠標移動了很小的距離-無需單擊任何鼠標。 下面的機制可以檢測到這一點。 如果檢測到,我認為這是缺少觸摸支持的標志,或者如果支持,則在使用鼠標時意義不大。 如果未檢測到,則假定為觸摸設備。
編輯此方法可能無法滿足所有目的。 它可用於控制基於已加載頁面上的用戶交互(例如圖像查看器)激活的功能。 下面的代碼還會使mousemove事件綁定在沒有鼠標的設備上,因為它現在很突出。 其他方法可能更好。
大致來說,它是這樣的(對不起jQuery,但在純Javascript中類似):
var mousedown, first, second = false;
var ticks = 10;
$(document).on('mousemove', (function(e) {
if(UI.mousechecked) return;
if(!first) {
first = e.pageX;
return;
}
if(!second && ticks-- === 0) {
second = e.pageX;
$(document).off('mousemove'); // or bind it to somewhat else
}
if(first && second && first !== second && !mousedown){
// set whatever flags you want
UI.hasmouse = true;
UI.touch = false;
UI.mousechecked = true;
}
return;
}));
$(document).one('mousedown', (function(e) {
mousedown = true;
return;
}));
$(document).one('mouseup', (function(e) {
mousedown = false;
return;
}));
您可以使用以下代碼:
function isTouchDevice() {
var el = document.createElement('div');
el.setAttribute('ongesturestart', 'return;'); // or try "ontouchstart"
return typeof el.ongesturestart === "function";
}
來源: 檢測基於觸摸的瀏覽和@mplungjan post 。
以上解決方案基於檢測事件支持而無需瀏覽器嗅探的文章。
您可以在以下測試頁面上檢查結果。
請注意,以上代碼僅測試瀏覽器是否支持觸摸,而不測試設備。 因此,如果您的筆記本電腦帶有觸摸屏,則您的瀏覽器可能不支持觸摸事件。 最新的Chrome支持觸摸事件 ,但其他瀏覽器可能不支持。
您也可以嘗試:
if (document.documentElement.ontouchmove) {
// ...
}
但它可能不適用於iPhone設備。
$.support.touch ? "true" : "false";
如果你測試 document.documentElement 支持 touchstart 就這么簡單
var x = 'touchstart' in document.documentElement; console.log(x) // return true if is supported // else return false
雖然它只是在 alpha 中,但jquery 移動框架值得一試。 它將跨移動瀏覽器規范這些類型的事件。 也許看看他們在做什么。 我假設 jquery-mobile.js 與這個框架不同。
這種方式對我有用,它等待第一次用戶交互以確保他們在觸摸設備上
var touchEnabled = false;
$(document.body).one('touchstart',
function(e){
touchEnabled=true;
$(document.documentElement).addClass("touch");
// other touch related init
//
}
);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.