Iframe предотвращает прокрутку iScroll на мобильном Safari
Я использую iScroll на моем мобильном веб-сайте (используя iPhone здесь) для прокрутки внутри div.
В этом div, у меня есть iframe с фиксированной высотой, как это:
<body>
<div id="iscroller">
<iframe id="theIframe"></iframe>
Other stuff
</div>
</body>
Теперь, прокручивая в div, все работает так, как ожидалось, но я не могу прокручивать, когда прокручивающий жест начинается с iframe.
Проблема описана здесь довольно хорошо: https://github.com/cubiq/iscroll/issues/41
Итак, я использовал обходное решение css из этого сообщения, применив pointer-events:none
к iframe.
Теперь прокрутка отлично работает , но. Я не могу щелкнуть ссылки, определенные в iframe, потому что все события click/touch в iframe, кажется, заблокированы из-за pointer-events: none
.
Итак, я подумал:
"Хорошо, пока пользователь прокручивает, мне нужно pointer-events:none
. Если он не прокручивая (и вместо этого щелкая), я должен установить pointer-events:auto
чтобы пропускать события щелчка/касания."
Итак, я сделал это:
CSS
#theIframe{pointer-events:none}
JavaScript
$("#theIframe").bind("touchstart", function(){
// Enable click before click is triggered
$(this).css("pointer-events", "auto");
});
$("#theIframe").bind("touchmove", function(){
// Disable click/touch events while scrolling
$(this).css("pointer-events", "none");
});
Даже добавление этого не работает:
$("#theIframe").bind("touchend", function(){
// Re-enable click/touch events after releasing
$(this).css("pointer-events", "auto");
});
Независимо от того, что я делаю: прокрутка не работает или щелчок по ссылке внутри iframe не работает.
Не работает. Любые идеи?
Ответы
Ответ 1
Я нашел идеальное решение. Отлично работает на iOS и Android.
Основная идея состоит в том, чтобы поместить div-слой поверх этого iframe. Таким образом, прокрутка работает плавно.
Если пользователь хочет нажать/кликнуть на элементе на этом iframe, я просто поймаю, что нажимаю на этот слой, сохраняю координаты x и y и запускаю событие click для содержимого iframe в этих координатах:
HTML:
<div id="wrapper">
<div id="layer"></div>
<iframe id="theIframe"></iframe>
</div>
Other stuff
CSS
#layer{
position:absolute;
opacity:0;
width:100%;
height:100%;
top:0;
left:0;
right:0;
bottom:0;
z-index:2
}
JavaScript:
$('#layer').click(function(event){
var iframe = $('#theIframe').get(0);
var iframeDoc = (iframe.contentDocument) ? iframe.contentDocument : iframe.contentWindow.document;
// Find click position (coordinates)
var x = event.offsetX;
var y = event.offsetY;
// Trigger click inside iframe
var link = iframeDoc.elementFromPoint(x, y);
var newEvent = iframeDoc.createEvent('HTMLEvents');
newEvent.initEvent('click', true, true);
link.dispatchEvent(newEvent);
});
Ответ 2
Я нашел решение для этого, он оказался близким к тому, что другие ребята уже упомянули в github, но это может быть полезно для тех, кто хочет найти быстрое разрешение для этой проблемы.
Я принимаю несколько вещей, например, только один контейнер iscroll, представленный как ID. Это не проверено надлежащим образом и нуждается в рефакторе. Он работает в моем проекте, но я немного изменил его для примера, но, думаю, вы легко поймете, что вам нужно сделать:
var $iscroll = $('#iscroll');
document.addEventListener('touchstart', function(e) {
if ($iscroll.find('iframe').length > 0){
$.each($iscroll.find('iframe'), function(k,v){
var $parent = $(v).parent().first();
if ($parent.find('.preventTouch').length == 0){
$('<div class="preventTouch" style="position:absolute; z-index:2; width:100%; height:100%;"></div>')
.prependTo($parent);
};
$parent
.css('position', 'relative').css('z-index', 1);
});
$iscroll.find('.preventTouch').on('click', function(e){
e.preventDefault();
e.stopPropagation();
return false;
});
};
};
document.addEventListener('touchend', function(e) {
if ($iscroll.find('iframe').length > 0){
setTimeout(function(){
var $iscroll = $('#iscroll');
$iscroll.find('.preventTouch').remove();
$iscroll.find('iframe').css('z-index', '');
$iscroll.find('.preventTouch').off('click');
}, 400);
};
};
Спасибо, что посмотрели!