#javascript #mobile #mobile-website #touchscreen #zepto
#javascript #Мобильный #мобильный-веб-сайт #сенсорный экран #zepto
Вопрос:
Я пытаюсь создать поведение, аналогичное клавиатуре iPhone (см. прилагаемое изображение). Например, когда пользователь запускает и перемещает touch, он видит увеличенную версию элемента, к которому прикасаются, и выбор будет происходить при нажатии. Я использую Zepto.
Я могу правильно определить координаты касания, но у меня проблемы с поиском объекта, который находится под пальцем. Я использую приведенный ниже код, чтобы проверить, какой элемент возвращается в качестве цели события.
$("#myList li").live('touchmove', function(event) {
console.log(event.touches[0].target.innerHTML);
});
Это всегда возвращает событие, которое было при starttouch.
В документации Apple у касания должно быть событие event.touches event.changedTouches event.targetTouches
Я попытался проверить первый элемент на каждом из объектов, но все они, похоже, содержат только starttouch-элемент в качестве целевого. Есть ли что-то, чего я здесь не хватает?
Я правильно получаю координаты для касания из
var positionTop = event.touches[0].pageY;
var positionLeft = event.touches[0].pageX;
Если все остальное не удается, я начал думать, может быть, есть способ найти DOM-элемент под касанием с координатами.
Приветствуются любые идеи.
Ответ №1:
Объект, который находится под событием касания, задается event.target
. Кроме того, вы должны привязываться к touchstart
и touchend
событиям. Смотрите этот пример, который я сделал:
http://ampersand.no.de/iOSkeyboard.html
Исходный код:
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
<style>
body{
font-family:arial;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-o-user-select: none;
user-select: none;
}
.entry{
border:1px solid green;
color:darkGreen;
margin:25px;
font-size:25px;
font-family:verdana, arial,"sans serif";
padding:10px;
width:500px;
word-wrap:break-word;
}
.wrapper{
height:200px;
position:relative;
margin:25px;
}
.keyboard{
position:absolute;
bottom:0;
}
.key{
border:1px solid darkGray;
display:inline-block;
text-align:center;
cursor:pointer;
margin-top:1px;
border-radius: 4px;
font-family:arial,"sans serif";
width:30px;
height:30px;
line-height:30px;
}
.shift{
width:60px;
margin-left:35px;
}
.spacebar{
width:126px;
}
.backspace{
width:60px;
}
.keypress{
border:1px solid blue;
}
#floatKey{
border-bottom-left-radius:10px;
border-bottom-right-radius:10px;
border-bottom:0px;
border-color:blue;
font-weight:bold;
font-size:24px;
cursor:pointer;
width:40px;
height:40px;
line-height:40px;
background-color:white;
-moz-box-shadow: -5px 0px 5px #ccc;
-webkit-box-shadow: -5px 0px 5px #ccc;
box-shadow: -5px 0px 5px #ccc;
}
.touchStart{
border-color:blue;
border-top:0px;
border-top-left-radius:0px;
border-top-right-radius:0px;
-moz-box-shadow: -5px 5px 5px #ccc;
-webkit-box-shadow: -5px 5px 5px #ccc;
box-shadow: -5px 5px 5px #ccc;
}
</style>
</head>
<body>
<h3>iOS-style keyboard examples</h3>
<div class="entry">|</div>
<div class="wrapper">
<div>With mouse events:</div>
<div class="keyboard" id="mousekb">
<div class="row">
<span>1</span>
<span>2</span>
<span>3</span>
<span>4</span>
<span>5</span>
<span>6</span>
<span>7</span>
<span>8</span>
<span>9</span>
<span>0</span>
</div>
<div class="row">
<span>q</span>
<span>w</span>
<span>e</span>
<span>r</span>
<span>t</span>
<span>y</span>
<span>u</span>
<span>i</span>
<span>o</span>
<span>p</span>
</div>
<div class="row" style="margin-left:18px">
<span>a</span>
<span>s</span>
<span>d</span>
<span>f</span>
<span>g</span>
<span>h</span>
<span>j</span>
<span>k</span>
<span>l</span>
</div>
<div class="row">
<span>z</span>
<span>x</span>
<span>c</span>
<span>v</span>
<span>b</span>
<span>n</span>
<span>m</span>
<span>,</span>
<span>.</span>
</div>
<div class="row">
<span class="shift">shift</span>
<span class="spacebar">amp;nbsp;</span>
<span class="backspace">amp;lArr;</span>
</div>
</div>
</div>
<div class="entry">|</div>
<div class="wrapper">
<div>With touch events (zoom in for better view):</div>
<div class="keyboard" id="touchkb">
<div class="row">
<span>1</span>
<span>2</span>
<span>3</span>
<span>4</span>
<span>5</span>
<span>6</span>
<span>7</span>
<span>8</span>
<span>9</span>
<span>0</span>
</div>
<div class="row">
<span>q</span>
<span>w</span>
<span>e</span>
<span>r</span>
<span>t</span>
<span>y</span>
<span>u</span>
<span>i</span>
<span>o</span>
<span>p</span>
</div>
<div class="row" style="margin-left:18px">
<span>a</span>
<span>s</span>
<span>d</span>
<span>f</span>
<span>g</span>
<span>h</span>
<span>j</span>
<span>k</span>
<span>l</span>
</div>
<div class="row">
<span>z</span>
<span>x</span>
<span>c</span>
<span>v</span>
<span>b</span>
<span>n</span>
<span>m</span>
<span>,</span>
<span>.</span>
</div>
<div class="row">
<span class="shift">shift</span>
<span class="spacebar">amp;nbsp;</span>
<span class="backspace">amp;lArr;</span>
</div>
</div>
</div>
<div id="floatKey" class="key" style="display:none"></div>
<script>
SHIFT=false;
$('.keyboard span').addClass('key');
function touchStart(ev){
ev.preventDefault();
var o=$(ev.target).offset();
$('#floatKey').html($(ev.target).html())
.show()
.offset({top:(o.top-$('#floatKey').outerHeight()), left:(o.left-5)});
$(ev.target).addClass('touchStart');
}
function touchEnd(ev){
ev.preventDefault();
$('#floatKey').hide();
$(ev.target).removeClass('touchStart');
}
function keyrelease(ev){
ev.preventDefault();
outlineKey(ev.target);
$(ev.target).removeClass('keydown');
$('#floatKey').removeClass('keydown');
var text=$('.entry').eq(0).text();
$('.entry').text(text.substr(0,text.length-1) $(ev.target).text() '|');
}
function shiftKey(ev){
ev.preventDefault();
if(SHIFT){
$('.keyboard span').not('.shift').each(function(idx,el){
$(el).text($(el).text().toLowerCase());
})
$(ev.target).removeClass('keypress');
SHIFT=false;
}else{
$('.keyboard span').not('.shift').each(function(idx,el){
$(el).text($(el).text().toUpperCase());
})
$(ev.target).addClass('keypress');
SHIFT=true;
}
}
function outlineKey(el){
$(el).addClass('keypress');
setTimeout(function(){
$(el).removeClass('keypress')
},500);
}
function backspace(ev){
ev.preventDefault();
outlineKey(ev.target);
var text=$('.entry').eq(0).text();
$('.entry').text(text.substr(0,text.length-2) '|');
}
//mouse keyboard
$('#mousekb span').not('.spacebar,.shift,.backspace').bind('mouseenter',touchStart);
$('#mousekb span').not('.spacebar,.shift,.backspace').bind('mouseout',touchEnd)
$('#mousekb span').not('.shift,.backspace').bind('mouseup',keyrelease)
$('#mousekb .shift').bind('mouseup',shiftKey);
$('#mousekb .backspace').bind('mouseup',backspace);
//touch keyboard:
$('#touchkb span').not('.spacebar,.shift,.backspace').bind('touchstart',touchStart);
$('#touchkb span').not('.spacebar,.shift,.backspace').bind('touchend',touchEnd);
$('#touchkb span').not('.shift,.backspace').bind('touchend',keyrelease)
$('#touchkb .shift').bind('touchend',shiftKey);
$('#touchkb .backspace').bind('touchend',backspace);
</script>
</body>
Обновить
Хорошо, я нашел это, и «это» называется document.getElementFromPoint()
. На сайте Mozilla есть некоторая документация (https://developer.mozilla.org/En/DOM/Document.elementFromPoint ). Он получит элемент с заданными верхними и левыми координатами. Это можно легко использовать для отслеживания того, над какой клавишей в данный момент находится палец. Я обновил свой пример кода, чтобы использовать эту потрясающую функцию. Вот некоторые обновленные функции, которые получают текущий элемент касания и обновляют «клавишу наведения»:
//functions for touchmove implementation:
function getElAtTouchPosition(ev){
var touch = ev.originalEvent.touches[0] || ev.originalEvent.changedTouches[0] || ev.touches[0];
var top = touch.pageY;
var left = touch.pageX;
var el=document.elementFromPoint(left,top);
if(el.className=='key'){
return el;
}else{
return null;
}
}
function move(ev){
ev.stopImmediatePropagation();
var el=getElAtTouchPosition(ev);
if(el.className=='key' amp;amp; el!=currentHoverKey){
updateFloatKey(el);
currentHoverKey=el;
}
}
function updateFloatKey(el){
var o=$(el).offset();
$(currentHoverKey).removeClass('touchStart');
$('#floatKey').html($(el).html())
.show()
.offset({top:(o.top-$('#floatKey').outerHeight()), left:(o.left-5)});
$(el).addClass('touchStart');
}
function touchStart2(ev){
ev.preventDefault();
updateFloatKey(ev.target);
currentHoverKey=ev.target;
}
function touchStop2(ev){
$(currentHoverKey).removeClass('touchStart');
$('#floatKey').hide();
}
Ознакомьтесь с примером, чтобы увидеть, как все это используется. Я протестировал это на iPad 2 (iOS 4.3), и это работает. Он все еще нуждается в некоторой настройке для улучшения плавности и учета случаев, когда touchmove заканчивается на неключевом элементе. Мне было бы интересно посмотреть, как это работает на Android. Я еще не завершил ввод кода текста для третьей клавиатуры, но вы можете объединить некоторые из моих предыдущих кодов, чтобы заставить его работать. Удачи.
Примечание: Чрезвычайно важно блокировать распространение события touchmove / всплывание вверх по дереву DOM. Если он будет распространяться, то он превратится в прокрутку, а во время прокрутки на устройствах iOS управление DOM отключено, поэтому вы не сможете обновить «клавишу наведения». Вам необходимо учитывать все крайние случаи, когда событие touchmove срабатывает над неключевым элементом.
Комментарии:
1. «Это» (document.getElementFromPoint()) — это именно то, чего я не нашел :). Я надеялся, что такая функция найдется, но нигде не смог ее найти.
2. @Marcus, мне было бы очень, очень интересно увидеть вашу окончательную реализацию этого типа клавиатуры. Если ваш сайт общедоступен, пожалуйста, разместите ссылку! Спасибо.
3. Может пройти некоторое время, прежде чем это станет достоянием общественности, но когда это произойдет, я постараюсь опубликовать ссылку здесь. Спасибо вам за отличную находку document.getElementFromPoint и за хороший пример. Я почти уверен, что такого рода интерфейсы для мобильных устройств / touch станут более популярными в будущем.