上一篇文章中说明了如何iframe的父子级之间如何传递信息,但是获取iframe子页面滚动高度的效果并不是很理想。

可能出现的问题:

1.特殊场景下会出现双重滚动条,影响体验

2.即时是加了setTimeout()定时器函数,有的时候也不能够取得准确的scrollHeight的值,例如iframe子页面有很多图片,图片加载过程就会影响到页面的高度。

优化:

考虑到上述问题,开始寻求其他方式来监听iframe子页面的滚动高度值。

经大神提点,建议在iframe子页面中监听整个页面容器的高度,类似于监听div的高度变化,每次变化都向firame父页面传递高度值。找到了两个API:

MutationObserver

MutationObserver的MDN文档

本以为这就好用了,网上很多文章也说的很详细,比如 HTML5新特性之Mutation Observer,可监听到子元素的变动、属性的变动、文本的变动等等,这就给我一种错觉,它可以监听到div的宽高,所以我花了很长时间来调这个东西,上代码,这个是iframe的子页面中写的

mounted() {
    this.observed()
  },
  methods: {
    observed() {
      var targetNode = document.getElementById('currentContainer');
      var config = { attributes: true, childList: true, characterData: true, subtree: true };
      var recordHeight = 0;
      var mutationObserver = new MutationObserver(function (mutations) {
        console.log(mutations);
        let height = getComputedStyle(targetNode).getPropertyValue('height')
        if(height == recordHeight){
          return
        }
        recordHeight = height
        console.log("高度发生变化", document.body.scrollHeight, recordHeight)
        window.parent.postMessage(document.body.scrollHeight, "/");
      })
      mutationObserver.observe(targetNode, config)
    }
  }

我感觉本身写的没有问题,但就是不好使,继续在网上找资料。。。

直到我看到了这篇文章,html5 mutation observer 不能监听元素尺寸变化,还有何用?,这里提到了ResizeObserver,拯救了我!!!

ResizeObserver

ResizeObserver的MDN文档

这回不直接往vue里写了,先写个测试,添加了防抖,可能用节流会更好一些,这个防抖携带argument的。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>123</title>

    <style>
        .box {
            width: 200px;
            height: 20vh;
            border: 1px solid red;
        }
    </style>
</head>

<body>
    <div id="ss" class="box"></div>
    <script>
        function debounce(func, wait) {
            let timer;
            return function () {
                let context = this; // 注意 this 指向
                let args = arguments; // arguments中存着e

                if (timer) clearTimeout(timer);

                timer = setTimeout(() => {
                    func.apply(this, args)
                }, wait)
            }
        }

        function addResizeListen(dom, callback) {
            new ResizeObserver(entries => {
                if (callback) callback(entries)
            }).observe(dom);
        }
        addResizeListen(document.getElementById('ss'), debounce((entries) => {
            for (let entry of entries) {
                console.log(Math.round(entries[0].contentRect.height));
            }
        }, 500))
    </script>
</body>

</html>

呕吼,发现好用,赶紧放到vue里面,也就是iframe的子页面中

 mounted() {
    this.addResizeListen(
      document.getElementById("currentContainer"),
      this.debounce((entries) => {
        for (let entry of entries) {
          let height = Math.round(entries[0].contentRect.height + 570);
          window.parent.postMessage(document.body.scrollHeight, "/");
        }
      }, 500)
    );
  },
  methods: {
    addResizeListen(dom, callback) {
      new ResizeObserver((entries) => {
        if (callback) callback(entries);
      }).observe(dom);
    },
    debounce(func, wait) {
      let timer;
      return function () {
        let context = this;
        let args = arguments;
        if (timer) clearTimeout(timer);
        timer = setTimeout(() => {
          func.apply(this, args);
        }, wait);
      };
    },
  },

然后再禁用一下iframe子页面的滚动条

body
  overflow-x hidden
  overflow-y hidden

打包测试,完美! 万岁!!!

Logo

前往低代码交流专区

更多推荐