Das Problem
Ich helfe bei der Pflege einer großen, komplizierten, chaotischen alten Site, auf der alles (im wahrsten Sinne des Wortes) in mehreren Ebenen von Iframes verschachtelt ist - von denen viele dynamisch erstellt werden und / oder einen dynamischen Quellcode haben. Das schafft folgende Herausforderungen:
- Bei Änderungen an der HTML-Struktur können Skripte und Stylesheets beschädigt werden, die seit Jahren nicht mehr berührt wurden.
- Das manuelle Suchen und Reparieren aller iframes- und src-Dokumente würde viel zu viel Zeit und Mühe kosten.
Von den bisher veröffentlichten Lösungen ist dies die einzige, die ich gesehen habe, die Herausforderung 1 überwindet. Leider scheint es bei einigen Iframes nicht zu funktionieren, und wenn dies der Fall ist, ist das Scrollen sehr fehlerhaft (was andere zu verursachen scheint) Fehler auf der Seite, z. B. nicht reagierende Links und Formularsteuerelemente).
Die Lösung
Wenn das oben Gesagte Ihrer Situation entspricht, können Sie das folgende Skript ausprobieren. Es verzichtet auf natives Scrollen und macht stattdessen alle Iframes innerhalb der Grenzen ihres Ansichtsfensters ziehbar. Sie müssen es nur dem Dokument hinzufügen, das die Iframes der obersten Ebene enthält. Das Update wird nach Bedarf auf sie und ihre Nachkommen angewendet.
Hier ist eine funktionierende Geige * und hier ist der Code:
(function() {
var mouse = false //Set mouse=true to enable mouse support
, iOS = /iPad|iPhone|iPod/.test(navigator.platform)
if(mouse || iOS) {
(function() {
var currentFrame
, startEvent, moveEvent, endEvent
, screenY, translateY, minY, maxY
, matrixPrefix, matrixSuffix
, matrixRegex = /(.*([\.\d-]+, ?){5,13})([\.\d-]+)(.*)/
, min = Math.min, max = Math.max
, topWin = window
if(!iOS) {
startEvent = 'mousedown'
moveEvent = 'mousemove'
endEvent = 'mouseup'
}
else {
startEvent = 'touchstart'
moveEvent = 'touchmove'
endEvent = 'touchend'
}
setInterval(scrollFix, 500)
function scrollFix() {fixSubframes(topWin.frames)
function fixSubframes(wins) {for(var i = wins.length
function addListeners(win) {
try {
var doc = win.document
if(!doc.draggableframe) {
win.addEventListener('unload', resetFrame)
doc.draggableframe = true
doc.addEventListener(startEvent, touchStart)
doc.addEventListener(moveEvent, touchMove)
doc.addEventListener(endEvent, touchEnd)
}
fixSubframes(win.frames)
}
catch(e) {}
}
function resetFrame(e) {
var doc = e.target
, win = doc.defaultView
, iframe = win.frameElement
, style = getComputedStyle(iframe).transform
if(iframe===currentFrame) currentFrame = null
win.removeEventListener('unload', resetFrame)
doc.removeEventListener(startEvent, touchStart)
doc.removeEventListener(moveEvent, touchMove)
doc.removeEventListener(endEvent, touchEnd)
if(style !== 'none') {
style = style.replace(matrixRegex, '$1|$3|$4').split('|')
iframe.style.transform = style[0] + 0 + style[2]
}
else iframe.style.transform = null
iframe.style.WebkitClipPath = null
iframe.style.clipPath = null
delete doc.draggableiframe
}
function touchStart(e) {
var iframe, style, offset, coords
, touch = e.touches ? e.touches[0] : e
, elem = touch.target
, tag = elem.tagName
currentFrame = null
if(tag==='TEXTAREA' || tag==='SELECT' || tag==='HTML') return
for(
if(elem.scrollHeight > elem.clientHeight) {
style = getComputedStyle(elem).overflowY
if(style==='auto' || style==='scroll') return
}
}
elem = elem.ownerDocument.body
iframe = elem.ownerDocument.defaultView.frameElement
coords = getComputedViewportY(elem.clientHeight < iframe.clientHeight ? elem : iframe)
if(coords.elemTop >= coords.top && coords.elemBottom <= coords.bottom) return
style = getComputedStyle(iframe).transform
if(style !== 'none') {
style = style.replace(matrixRegex, '$1|$3|$4').split('|')
matrixPrefix = style[0]
matrixSuffix = style[2]
offset = parseFloat(style[1])
}
else {
matrixPrefix = 'matrix(1, 0, 0, 1, 0, '
matrixSuffix = ')'
offset = 0
}
translateY = offset
minY = min(0, offset - (coords.elemBottom - coords.bottom))
maxY = max(0, offset + (coords.top - coords.elemTop))
screenY = touch.screenY
currentFrame = iframe
}
function touchMove(e) {
var touch, style
if(currentFrame) {
touch = e.touches ? e.touches[0] : e
style = min(maxY, max(minY, translateY + (touch.screenY - screenY)))
if(style===translateY) return
e.preventDefault()
currentFrame.contentWindow.getSelection().removeAllRanges()
translateY = style
currentFrame.style.transform = matrixPrefix + style + matrixSuffix
style = 'inset(' + (-style) + 'px 0px ' + style + 'px 0px)'
currentFrame.style.WebkitClipPath = style
currentFrame.style.clipPath = style
screenY = touch.screenY
}
}
function touchEnd() {currentFrame = null
function getComputedViewportY(elem) {
var style, offset
, doc = elem.ownerDocument
, bod = doc.body
, elemTop = elem.getBoundingClientRect().top + elem.clientTop
, elemBottom = elem.clientHeight
, viewportTop = elemTop
, viewportBottom = elemBottom + elemTop
, position = getComputedStyle(elem).position
try {
while(true) {
if(elem === bod || position === 'fixed') {
if(doc.defaultView.frameElement) {
elem = doc.defaultView.frameElement
position = getComputedStyle(elem).position
offset = elem.getBoundingClientRect().top + elem.clientTop
viewportTop += offset
viewportBottom = min(viewportBottom + offset, elem.clientHeight + offset)
elemTop += offset
doc = elem.ownerDocument
bod = doc.body
continue
}
else break
}
else {
if(position === 'absolute') {
elem = elem.offsetParent
style = getComputedStyle(elem)
position = style.position
if(position === 'static') continue
}
else {
elem = elem.parentElement
style = getComputedStyle(elem)
position = style.position
}
if(style.overflowY !== 'visible') {
offset = elem.getBoundingClientRect().top + elem.clientTop
viewportTop = max(viewportTop, offset)
viewportBottom = min(viewportBottom, elem.clientHeight + offset)
}
}
}
}
catch(e) {}
return {
top: max(viewportTop, 0)
,bottom: min(viewportBottom, doc.defaultView.innerHeight)
,elemTop: elemTop
,elemBottom: elemBottom + elemTop
}
}
})()
}
})()
* Für die jsfiddle ist die Mausunterstützung zu Testzwecken aktiviert. Auf einer Produktionsstätte möchten Sie mouse = false setzen.