在iframe上滑动时如何移动父元素?

时间:2013-06-12 22:03:35

标签: javascript jquery html css slider

我有一个滑块,可以通过touchmove事件检测滑动并相应地移动内容。但是,当内容中有iframe,并且我将手指滑过iframe时,页面将不会移动,因为touchmove事件被iframe本身拦截,而不是父页面。因此,父div不会移动。

这个iframe也需要保持可点击状态,因为它是一个广告所以我不能用另一个具有更高z-index的div覆盖它。

我可以在Javascript中将touchmove事件冒泡到父级?他们在同一个域名上。任何帮助将不胜感激!

我使用的滑块就是这个 - http://dezignhero.github.io/swiper.js/(当页面中没有iframe时工作正常)

var Swiper = function(selector, options) {

/*------- Globals -------*/

var viewportWidth = 0,
    frameWidth = 0,
    animating = false,
    numSlides = 0,
    limitEnd = 0,
    goTo = 0,
    currentSlide = 0,
    orientation = 0;

// Swiping
var swipe = {
    started : false,
    startX : 0,
    endX : 0,
    at : 0,
    strength : 0
};

// Settings
var settings = {
    ease : 0.3,
    swipeMin : 40,
    preventAdvance : false,
    container : '.container',
    frame : '.page',
    frameWidth : false,  // accepts a number in pixels
    controls : '.control',
    clickEvent : 'click',
    updateEvent : 'update',
    controlsOnly : false,
};

/*------- Handles -------*/

var el = selector,
    $parent = $(el),
    $container, $controls, $frame, $prevCtrl, $nextCtrl;

/*------- Methods -------*/

var init = function(options) {
    // Exit if element doesn't exist
    if ( $(el).length == 0 ) return;

    // Merge settings
    settings = $.extend(settings, options || {});

    // Initialize handles
    $container = $(settings.container, el);
    $controls = $(settings.controls, el);
    $frame = $(settings.frame, el);

    // Assign Ids to frames
    $frame.each(function(i){
        $(this).attr('data-id', i);
        numSlides++;
    });

    // Add initial class
    $($frame.selector+'[data-id=0]', el).addClass('current');

    // Set Dimensions
    resize();

    // Setup CSS
    $container.css({
        '-webkit-transition' : 'all '+settings.ease+'s ease-out',
        '-webkit-transform' : 'translate3d(0,0,0)',  // Performance optimization, put onto own layer for faster start
        'left' : 0
    });

    // Monitoring controls if they exist
    if ( $controls.length > 0 ) {
        // Determine whether or not to use click event
        if ('ontouchstart' in document.documentElement) {
            settings.clickEvent = 'touchstart';
        }

        // Create handlers
        $prevCtrl = $(settings.controls+'[data-action=prev]');
        $nextCtrl = $(settings.controls+'[data-action=next]');

        // Bind behavior
        $controls.on(settings.clickEvent, function(){
            var self = $(this),
                action = self.attr('data-action');

            // Ensure action defined
            if ( typeof action == 'undefined' ) return;

            if ( action == 'next' && currentSlide < numSlides - 1 ) {
                goTo = currentSlide + 1;
            } else if ( action == 'prev' && currentSlide > 0 ) {
                goTo = currentSlide - 1;
            }

            // Move container
            jumpTo(goTo);
        });
    }

    // Display controls correctly
    if ( settings.preventAdvance ) {
        disableSliding();
    } else {
        updateControls();
    }

    // Swiping
    if ( !settings.controlsOnly ) {
        $container[0].addEventListener('touchstart', function(e) { touchStart(e); }, false);
        $container[0].addEventListener('touchmove', function(e) { touchMove(e); }, false);
        $container[0].addEventListener('touchend', function(e) { touchEnd(e); }, false);
        // Desktop
        $container[0].addEventListener('mousedown', function(e) { touchStart(e); }, false);
        $container[0].addEventListener('mousemove', function(e) { if (e.which==1) { touchMove(e); } }, false);
        $container[0].addEventListener('mouseup', function(e) { touchEnd(e); }, false);
    }

    // Prevent anchor tags from getting in the way
    $('a', el).on('touchstart click', function(){
        return swipe.started ? false : true;
    });

    // Prevent image dragging on getting in the way
    $('img', el).on('dragstart', function(){
        return false;
    });

    // Check if Android
    var ua = navigator.userAgent.toLowerCase(),
        isAndroid = ua.indexOf("android") > -1;

    // Orientation Change
    var supportsOrientationChange = "onorientationchange" in window,
        orientationEvent = (supportsOrientationChange && !isAndroid) ? "orientationchange" : "resize";

    // Listener for orientation changes
    window.addEventListener(orientationEvent, function() {
        // Prevent 'fake' orientation calls
        if ( orientation != window.orientation ) {
            orientation = window.orientation;
            resize(function(){
                jumpTo(currentSlide);
            });
        }
    }, false);
},

resize = function(callback){
    viewportWidth = $parent.width();
    frameWidth = ( settings.frameWidth ) ? settings.frameWidth : viewportWidth;

    // Apply new sizes
    $frame.width(frameWidth);
    $container.width(frameWidth*numSlides);

    // Set end limit
    limitEnd = settings.frameWidth ? viewportWidth/frameWidth : numSlides;

    // callback
    if ( typeof callback == 'function' ) {
        callback();
    }
},

touchStart = function(e) {
    swipe.at = getPosition();  // for touch move
    // Get start point
    swipe.startX = e.touches ? e.touches[0].pageX : e.pageX;
    swipe.startY = e.touches ? e.touches[0].pageY : e.pageY;
    swipe.endX = swipe.startX;  // prevent click swiping when touchMove doesn't fire
},

touchEnd = function(e) {
    swipe.started = false;

    // Nullify event
    e.preventDefault();

    if ( animating ) return;

    var moved = swipe.endX - swipe.startX,
        threshold = frameWidth / 3;

    goTo = currentSlide;

    // Figure out closest slide
    if ( Math.abs(moved) > threshold || swipe.strength > settings.swipeMin ) {
        if ( moved > 0 && currentSlide > 0 ) {
            goTo--;
        } else if ( moved < 0 && currentSlide < limitEnd-1 ) {
            goTo++;
        }
    }

    // Jump to closest        
    jumpTo(goTo);
},

touchMove = function(e) {
    if ( !$parent.hasClass('disabled') ) {
        swipe.started = true;
        var touchX = e.touches ? e.touches[0].pageX : e.pageX,
            touchY = e.touches ? e.touches[0].pageY : e.pageY,
            dX = touchX - swipe.startX,
            dY = touchY - swipe.startY;

        swipe.strength = Math.abs(touchX - swipe.endX);
        swipe.endX = touchX;

        // Escape if motion wrong
        if ( Math.abs(dX) < Math.abs(dY) ) return;

        e.preventDefault();

        // Always run this so that hit the ends
        animate(swipe.at+dX, false);
    }
},

getPosition = function() {
    // Get current point and Stay there
    var style = document.defaultView.getComputedStyle($container[0], null),
        transform = new WebKitCSSMatrix(style.webkitTransform);

    // Return position based on direction
    return transform.m41;
},

animate = function(scrollTo, ease) {
    // Momentum Effect or Not
    $container[0].style.webkitTransition = ( ease ) ? 'all '+settings.ease+'s ease-out' : 'none';
    $container[0].style.webkitTransform = 'translate3d('+scrollTo+'px,0,0)';

    // Allow animating again
    if ( ease ) {
        animating = true;
        window.setTimeout(function(){
            animating = false;
        }, settings.ease*1000);
    }
},

jumpTo = function(num, ease) {
    // Keep within range
    if ( num >= 0 && num < limitEnd ) {

        // Animate
        var hasEase = ( typeof ease !== 'undefined' ) ? ease : true;
        animate(-num*frameWidth, hasEase);

        // If new slide
        if ( num != currentSlide ) {
            // Update current slide
            currentSlide = num;

            // Update current slide
            $frame.removeClass('current');
            $($frame.selector+'[data-id='+currentSlide+']').addClass('current');

            // Update parent to trigger update event and new slide
            $parent.trigger(settings.updateEvent, [ currentSlide, Math.floor(limitEnd) ]);

            // Control Buttons
            updateControls();

            // Disable Again
            if ( settings.preventAdvance ) {
                disableSliding();
            }
        }
    }
},

updateControls = function() {
    // Only run if controls exist
    if ( $controls.length == 0 ) return;

    if ( currentSlide >= 0 && currentSlide < limitEnd ) {
        $controls.show();
        if ( currentSlide == 0 ) {
            $prevCtrl.hide();
        } else if ( currentSlide == limitEnd-1 ) {
            $nextCtrl.hide();
        }   
    } else {
        $controls.hide();
    }
},

disableSliding = function() {
    // Hide Controls
    $('.control', el).hide();
    // Add disabled flag
    $parent.addClass('disabled');
},

enableSliding = function() {
    // Enable control buttons
    updateControls();
    // Remove disabled flag
    $parent.removeClass('disabled');
};

// Initialize the object
init(options);

return {

    element : $parent,

    jumpTo : jumpTo,

    swiping : function() {
        return swipe.started;
    },

    disableSliding : disableSliding,

    enableSliding : enableSliding,

    status : function() {
        return {
            'current' : currentSlide+1,
            'total' : numSlides
        }
    },

    next : function() {
        jumpTo(currentSlide+1);
    },

    prev : function() {
        jumpTo(currentSlide-1);  
    }
};

}

2 个答案:

答案 0 :(得分:1)

问题是iframe吞下了​​触摸事件。因此,如果有任何iframe,您在滑动的区域,您将无法滑动。我所知道的唯一解决方案是使用透明div覆盖iframe,并将任何点击事件发送到iframe。这样就可以在iframe上启用touchmove事件。

我已经在这里创建了一个基本的jquery插件。 https://gist.github.com/agaase/6971953

用法

$(selector).coverIframes();

这将涵盖带有透明div的$(选择器)内的任何iframe,并传输任何点击事件。

答案 1 :(得分:0)

我知道这是一个老问题,但您可以使用:

iframe {
  pointer-events: none;
}