移动端页面iframe问题

3,968 阅读2分钟

关于移动端iframe的一些坑,满满的干货

最近在做项目时,有一个需求时页面内要展示两个协议,分别是通过两个接口返回的url,然后把url赋值给iframe的src。页面的底部有个【提交】按钮,页面滑动到底部该按钮才能高亮并点击。

问题1: 如何给页面动态的设置高度,以此来达到不让iframe出现滚动条

首先,在iframe的父容器设置 height: 100%; overflow: scroll; scroll-behavior: smooth; position: relative;(这里的scroll-behavior是提供平滑滚动;相对定位后面能用到) 然后在iframe的onload事件里给iframe动态设置高度即可

iframe.onload = function() {
    iframe.height = iframe.contentDocument?.body?.scrollHeight || "100%";
}

问题2: 在页面上下滑动的过程中,我们手指触摸到的其实是iframe内的内容,这样如何能实现在父页面滑动到底部时,底部按钮高亮可点击呢?

重点到了 思路是这样的:

  • 禁止iframe滑动
  • 我们在父页面内用一个绝对定位的透明元素盖到iframe上面;然后透明元素的高度等于iframe的高度
    // 透明元素的css样式
    .parent {
        height: 100%;
        overflow: scroll;
        scroll-behavior: smooth;
        position: relative;
    }
    .mask {
        position: absolute;
        width: 100%;
        opacity: 0;
        z-index: 999;
    }
  • 父页面监听scroll事件即可 直接上代码
// 用的vue
function debounce(fn, time = 1000) {
    let timer = null;
    return v => {
        if (timer) {
            clearTimeout(timer);
        }
        timer = setTimeout(() => {
            fn(v);
        }, time);
    }
}

mounted() {
    // 这里 第三个参数要设置为true,不然移动端监听不到滑动事件
    // debounce防抖函数
    window.addEventListener('scroll', debounce(this.onScroll), true);
},
destroyed() {
    // 移除监听事件
    window.removeEventListener('scroll', debounce(this.onScroll), true);
},
methods: {
    onScroll() {
        let scrollTop = 父容器的scrollTop;
        // if (scrollTop > 两个iframe的高度之和 - 距离底部的安全距离) {
        if (scrollTop > this.totalIframeHeight - 500) {
            // 这里就可以让底部按钮高亮了
        }
    },
    // 动态设置iframe高度;禁止iframe可滑动
    // 这里的flag用来区分是哪个iframe;这里用top、bottom来区分上下两个iframe
    setIframeHeight(iframe, flag) {
        const that = this;
        iframe.onload = function() {
            iframe.height = iframe.contentDocument?.body?.scrollHeight || '100%';
            if (flag === 'top') {
                that.topIframeHeight = iframe.contentDocument?.body?.scrollHeight || 0;
                // 用变量来记录iframe是否加载成功
                that.hasTopIframeLoaded = true;
            } else if (flag === 'bottom') {
                that.hasBottomIframeLoaded = true;
                that.bottomIframeHeight = iframe.contentDocument?.body?.scrollHeight || 0;
                // 用变量来记录2个iframe的高度之和,在scroll事件中要用到
                if (that.hasTopIframeLoaded && that.hasBottomIframeLoaded) {
                    that.totalIframeHeight = that.topIframeHeight + that.bottomIframeHeight;
                }
                // 因为遇到的问题时第二个iframe滑动有问题,所以单独处理第二个
                if (iframe.contentDocument && iframe.contentDocument.body) {
                    // 这点很重要;不然Android上会有很神奇的bug
                    // 为啥不直接写iframe.contentDocument?.body?.style.overflow = 'hidden';因为编译会报错
                    iframe.contentDocument.body.style.overflow = 'hidden';
                }
                // 禁止iframe的滑动事件
                // 这里要用 { passive: false },而不是 false
                iframe.contentDocument?.body?.addEventListener(
                    'touchmove',
                    function(e) {
                        e.preventDefault();
                        e.stopPropagation();
                    }, { passive: false }
                )
            }
        }
    }
}

这样就能完美解决了,没有任何兼容性问题