Событие pointermove не работает с сенсорным экраном. Почему бы и нет?
У меня есть эта ручка:
https://codepen.io/anon/pen/eyKeqK
Если вы попробуете это на устройстве с сенсорным экраном (например, посетите перо на своем телефоне), вы заметите, что при перетаскивании белый свет (маленькая сфера) движется только на крошечный кусочек, затем он перестает работать.
Логика движения заключается в pointermove
обработчик события. Он отлично работает на рабочем столе с помощью мыши, но не с помощью касания.
Как это исправить, чтобы свет продолжал двигаться при перетаскивании касанием (не на мгновение), а в качестве бонуса, как мы можем предотвратить обновление страницы, когда мы нажимаем вниз?
Вот код для ручки:
HTML (тонкий):
/! Made with http://github.com/trusktr/infamous
script src="https://cdn.rawgit.com/trusktr/e37dbc24c51b9d3e2f9e508e75cf8f99/raw/2a3fee4ee506a05cc4ac509f592f0c3af1ddfed4/infamous-mixed-mode-3.js"
script src="https://unpkg.com/tween.js@16.6.0/src/Tween.js"
i-scene experimental-webgl="true" id="scene" TODO-perspective="800" backgroundColor="0 0 0" backgroundOpacity="0" style="perspective: 800px" shadowmap-type="pcfsoft"
i-ambient-light color="#404040" intensity="1"
i-dom-plane id="bg" sizeMode="proportional proportional" size="1 1 0"
i-node id="button-container" position="0 0 6" size="600 31 0" align="0.5 0.5 0" mountPoint="0.5 0.5 0"
- for n in (0..4)
i-dom-plane sizeMode="literal proportional" size="100 1 0" align="#{n*0.25} 0 0" mountPoint="#{n*0.25} 0 0"
button button #{n+1}
i-point-light id="light" color="white" position="300 300 120" size="0 0 0" cast-shadow="true" intensity="1"
i-mesh has="sphere-geometry basic-material" size="10 10 10" color="white" receive-shadow="false" cast-shadow="false" style="pointer-events: none"
CSS (Stylus):
body, html
width 100%
height 100%
margin 0
padding 0
font-family sans-serif
i-node
text-align center
#bg
background #62B997
button
width 100%
height 100%
white-space nowrap
border-radius 0px
border 1px solid #534334
background lighten(#FB752C, 20%)
color darken(#534334, 10%)
outline none // remove those darn ugly browser-specific outlines
&:focus, &:hover
background #FB752C
color darken(#534334, 20%)
JavaScript:
infamous.html.useDefaultNames()
const Motor = infamous.core.Motor
light.threeObject3d.shadow.radius = 3
light.threeObject3d.distance = 20000
light.threeObject3d.shadow.bias = 0.00001
document.addEventListener('pointermove', e => {
e.preventDefault()
light.position.x = e.clientX
light.position.y = e.clientY
})
let downTween, upTween, pressedButton
// On mouse down animate the button downward
document.addEventListener('pointerdown', e => {
if ( is( e.target, 'button' ) ) {
pressedButton = e.target
if (upTween) {
upTween.stop()
upTween = null
}
downTween = new TWEEN.Tween(e.target.parentNode.position)
.to({z: -6}, 75)
.start()
.onComplete(() => downTween = null)
Motor.addRenderTask(time => {
if (!downTween) return false
downTween.update(time)
})
}
})
// On mouse up animate the button upward
document.addEventListener('pointerup', e => {
if ( pressedButton ) {
if (downTween) {
downTween.stop()
downTween = null
}
upTween = new TWEEN.Tween(pressedButton.parentNode.position)
.to({z: 0}, 75)
.start()
.onComplete(() => upTween = null)
Motor.addRenderTask(time => {
if (!upTween) return false
upTween.update(time)
})
}
})
// The following is a temporary hack because opacity isn't
// exposed through the HTML API yet. work-in-progress...
setTimeout(() => {
Array.from( document.querySelectorAll('i-dom-plane') ).forEach(n => {
n.threeObject3d.material.opacity = 0.3
})
scene._needsToBeRendered()
}, 0)
function is( el, selector ) {
if ( [].includes.call( document.querySelectorAll( selector ), el ) ) return true
return false
}
1 ответ
На странице документации MDN о pointermove
есть эта строка:
Событие pointermove вызывается, когда указатель меняет координаты, и указатель не был отменен сенсорным действием браузера.
источник, акцент мой
Через короткий промежуток времени (мобильный) браузер запросит pointermove
Событие для "родного" поведения, как панорамирование страницы.
Разработанное простое решение - использовать свойство css. touch-action
и установите егоnone
на контейнере, который имеет обработчик событий.
Вот свойство css, добавленное в ваш кодовый блок: https://codepen.io/anon/pen/XVBMvL
Или в упрощенном примере:
- Настройте браузер на эмуляцию касания(в Chrome, dev. Tools > Sensors > Touch).
- Начните взаимодействие в левой части, и точка будет следовать за вашим пальцем
- Начните взаимодействие в правой части, и вы заметите, что оно быстро потерпит неудачу, как в приведенном примере.
var dot = document.querySelector(".dot")
document.body.addEventListener("pointermove", function(ev) {
dot.style.transform = `translate3d(${ev.clientX}px, ${ev.clientY}px, 0)`;
}, false);
* { margin: 0; padding: 0 }
.wrapper {
display: flex;
height: 100vh;
}
.hasTouchAction,
.noTouchAction {
flex-grow: 1;
text-align: center;
background: #efefef;
}
.hasTouchAction {
touch-action: none;
}
.noTouchAction {
background: #ccc;
}
.dot {
width: 16px;
height: 16px;
border-radius: 50%;
background: red;
position: absolute;
top: -8px;
left: -8px;
}
<div class="wrapper">
<div class="hasTouchAction">
With <code>touch-action: none</code>
</div>
<div class="noTouchAction">
Without <code>touch-action</code>
</div>
</div>
<div class="dot"></div>
Убедитесь, что вы не сломаете важные вещи и не повредите доступность. Также потратьте некоторое время на изучение поддержки браузера. Это работало для меня с событиями эмуляции касания в Chrome, но не могло бы работать в каждом браузере...