页面的滚动及scrollIntoView的穿透效果和解决

这篇具有很好参考价值的文章主要介绍了页面的滚动及scrollIntoView的穿透效果和解决。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

朋友今天遇到一个奇怪的问题,我觉得很有意思就记录一下。现象是这样的,页面有一个按钮,点击按钮以后会请求一个接口拿到一个iframe的地址然后创建一个iframe并渲染到页面上,iframe的页面加载完毕后会滑动到对应的某一个元素的位置,本来滑动是没问题的,但是父页面也跟着滑动了。现场的好几个领导就站在他后面盯着他解决,可想而知有多可怕了。他认为可能是iframe有锚点导致父页面受了影响,不过我并不认同这个想法,iframe的hash都对父元素有影响你这是看不起w3c还是看不起google。不过我也对这块不是很了解,正好今天不是很忙就想着动手试试复现,下面我简单记录一下问题的解决过程。

问题复现

在了解问题的现象以后我第一步就是按朋友的想法去复现问题,首先我创建了ab两个页面:

  <!-- a -->  
<body>
    <div class="home">
      <button>点击生成iframe</button>
    </div>
  </body>
  <script>
    const home = document.querySelector(".home");
    const btn = document.querySelector("button");
    btn.addEventListener("click", function (e) {
      const child = document.createElement("iframe");
      child.src = "http://127.0.0.1:5500/b.html";
      child.width = "800";
      child.height = "700";
      home.insertAdjacentElement("afterend", child);
    });
  </script>

  <!-- b -->
 <body>
    <div class="box">
      <div class="aaa"></div>
      <div id='target' class="bbb"></div>
    </div>
  </body>

样式我就不说了,大致就是点击按钮会生成iframe添加到a页面中,页面我用的live server还蛮方便的,我发现和我想的一样,和锚点根本没关系,说我google连这都处理不好?没道理的。不过既然滚动和锚点没关系那说明是iframe中有js让页面滚动了,于是我在b中添加js代码去滚动元素。

元素的滚动

这里我设置的.box高度是600,里面两个div的高度也都是600,上面.aaa是红色下面.bbb是天蓝色,这里我一共试了四种方案分别是:scrollTopscrollToscrollscrollIntoView,在我测试过程中发现只有**scrollIntoView**会出现朋友说的现象。

  <script>
    window.onload = function () {
      document.querySelector(".bbb").scrollIntoView({ behavior: "smooth" });
      // document.querySelector(".box").scrollTop = 600;
      // document.querySelector(".box").scrollTo({
      //   top: 600,
      //   behavior: "smooth",
      // });
      // document.querySelector(".box").scroll({
      //   top: 600,
      //   behavior: "smooth",
      // });
    };
  </script>

页面的滚动及scrollIntoView的穿透效果和解决,javascript

这里还是能很明显的看到问题所在的,在插入iframe以后首先是父页面滚动了一下然后iframe的内容滚动到目标位置。这个现象很奇怪,我查了MDN以及csswg都并没有说明这个现象,倒是在别处看到scrollIntoView不仅仅会让父容器滚动,父容器的容器有滚动条也会滚动的说法,这和我们看到的现象正好是一致的。所以我个人将这种现象称之为scrollIntoView的滚动的逆向穿透

解决方案

既然问题找到了下一步当然就是解决问题了,现在的问题是iframe是外部提供的我们没办法去更改iframe的代码,我朋友也是第一时间找了提供方的技术人员,那最合适的方式就是让那边的技术人员把**scrollIntoView的写法更改为其余三种的一种,不过我个人不推荐设置scrollTop**,没有过渡效果看起来不美观。

当然解决方案并不是只有这些,上面说的是最理想的情况了,不管是因为说炫技又或者说是iframe提供方支持不及时又或者其他原因,那我们能不能在父页面解决这个问题呢?下面简单分享一下解决的方法

一、事件监听(❌)

刚开始看效果我们很容易联想到一个事件相关的词——事件捕获,虽然我们没设置事件但是我想的是是否可以通过监听事件来控制对应的行为,使用 e.stopPropagation();去阻止按钮的默认行为我相信大多数人都是用过的,这里应该也是同理。

    document.onscroll = function () {
      e.stopPropagation();
    };

然而事情并没有如料想的一样,滑动无法被阻止,后来我查了一下发现scroll是一个UI事件,UI事件是不能被阻止的,因为这个只有变化完成了才会触发这个事件,我们没办法做到时空回溯。其实这里仔细想想就算是这个事件可以做到阻止滑动这里也有很大的局限性,因为如果阻止了页面的滑动就代表这个页面的一切滑动都被禁止了,包括原本父页面应该有的滑动,就算我们监听事件给的是一次性监听,但是对于事件和其他情况的兼容也是很复杂的,所以这个方法无论是理论还是实际其实都是不可行的。

二、重写滑动行为

其实在上个想法还没有得到验证的时候我脑海里就有了第二个想法——父页面写js去覆盖原有行为。这里经过朋友的提醒我这里分了两种情况分别是同步和异步。

1.同步情况覆盖

假设这个iframe的代码和我上面的案例是一样的都是在onload事件中去调用的scrollIntoView方法,那我们在父元素对iframe多添加一个onload事件,让后面的行为去覆盖前面的行为,最起码理论上是可行的

child.onload = function () {
  child.contentWindow.document.querySelector(".box").scrollTo({
    top: 600,
    behavior: "smooth",
  });
};

这里iframe的获取,因为我原生写的所以直接就可以拿到,Vue和React用户就自己用ref吧,拿到iframe的DOM实例以后我们可以通过contentWindow属性拿到iframe的window对象,因为我们添加的脚本一定是晚于iframe的自己的监听的,所以如果是相同的行为肯定是我们的行为去覆盖他原有的行为,我们看看效果如何:

页面的滚动及scrollIntoView的穿透效果和解决,javascript

不能说很好,只能说完美。

2.异步情况覆盖

本来到上面我都觉得已经大功告成,但是朋友提出了一个疑问,如果他的定位是在查询一个接口以后才进行的,你如何处理呢?这小子还挺会找问题,确实,因为我们是onload事件去写的脚本,所以如果他定位的代码是异步的,我们的脚本就失去意义了。朋友是想通过通信解决,让iframe要滑动的时候通信这边再改,我觉得有点本末倒置了,既然你都改iframe为啥不直接换个滑动方式,何必还通信多此一举呢,有点本末倒置了对吧。

那不然没办法解决了吗?其实问题的核心就在于我们不知道iframe的滑动代码是什么时候执行的,那有什么办法可以知道呢,其实通过一个监听就可以完成,还记得上面我说scrollIntoView的这个行为有点像捕获吗?父页面先滑动iframe的内容后滑动,所以我们给父页面添加一个scroll的监听,一旦监听触发就代表iframe的滑动代码执行了,然后我们更改滑动行为即可:

  document.onscroll = function () {
      child.contentWindow.document.querySelector(".box").scrollTo({
        top: 600,
        behavior: "smooth",
      });
    };

当然这个监听是一次性的了,毕竟这个方法副作用还是很大的,设置监听的时候可以用addEventListener然后给once属性即可。当然既然这个事件触发也就代表父页面其实是滚动了的,但是滚动时间触发的间隔其实是很短的 ,第一次触发的时候我们就覆盖了原有行为所以这里父页面的滚动只会触发一次,这一次估计也就几像素不仔细盯着看是看不出问题的。

3.补充

其实除了更改iframe滑动的行为方式以外,更多的解决方案是父元素滚动到原有位置

window.scrollTo({
    top:0
})

单就结果来说其实两种方式差别都不大,更多的是解决思路不同,不过无论是哪种解决思路最本质的都是在scrollIntoView的影响出现时去消除影响。如果影响的时机是已知的那就可以很方便的解决,但是如果是未知的可能就要采取监听滑动的方式去处理了。由监听滑动引出的一个比较重要的问题就是父页面滑动的触发方式,假设iframe的滑动行为要三秒后才执行,期间用户滑动了页面那我们的脚本要不要执行就是一个很大的问题,所以这里对于触发方式的判断也是很重要的。文章来源地址https://www.toymoban.com/news/detail-641541.html

到了这里,关于页面的滚动及scrollIntoView的穿透效果和解决的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 使用JavaScript实现页面滑动切换效果

      使用JavaScript实现页面滑动切换效果 在现代Web页面设计中,页面滑动切换效果已经成为了一种常见的设计要求,能够提升用户体验,增加页面的交互性。本文将通过JavaScript来实现这一效果。 首先,我们需要在HTML中添加一些基础结构和样式。以下是一个简单的例子:   在

    2024年02月13日
    浏览(38)
  • 小程序 解决自定义弹窗滚动穿透问题,解决弹窗背景内容滚动问题

    方法一、catchtouchmove=\\\"true\\\", 可以实现弹框背景不滚动,但是也会导致弹框自身无法滚动,如果你的弹窗本身是不需要滚动的,用这个方法是极佳的。 view class=\\\"pop\\\" catchtouchmove=\\\"true\\\"     view class=\\\"content\\\"/view /view 方法二、固定定位(可以解决背景不要滚动,弹框能滚动的问题)

    2024年02月03日
    浏览(26)
  • 微信小程序 movable-view 控制长按才触发拖动 轻轻滑动页面正常滚动效果

    今天写 movable-area+movable-view遇到了个头疼的问题 那就是 movable-view 监听了用户拖拽自己 但 我们小程序 上下滚动页面靠的也是拖拽 也就是说 如果放在这里 用户拖动 movable-view部分 就会永远触发不了滚动 那么 我们先可以 加一个 bindlongpress=\\\"longpressHandler\\\"事件 用户长按时触发 然

    2024年02月06日
    浏览(33)
  • 解决小程序自定义弹窗滚动穿透问题

    在小程序页面里有自定义弹窗时候,希望弹框里的scroll-view可以动,底部背景页面不要动 可以实现弹框背景不滚动,但是 也会导致弹框自身无法滚动 。 如果你的弹窗本身是不需要滚动的,用这个方法是极佳的。 设置 scroll-view 垂直滚动, 并将scroll-view的高度设置为屏幕高度

    2024年02月09日
    浏览(35)
  • 微信小程序 - 解决弹框遮罩层的滚动穿透问题

    在小程序页面里有自定义弹窗时候,发现弹窗外滚动的时候,底部背景页面也会跟随滚动。面对这个bug,我们可以用下面几种方法实现: 可以实现弹框背景不滚动,但是也会导致弹框自身无法滚动。 如果你的 弹窗本身是不需要滚动的 ,用这个方法是极佳的。 ps:开发工具测

    2024年02月17日
    浏览(41)
  • uni-app小程序 解决滚动穿透之page-meta

    页面是可以滚动的,该页面的弹窗、组件也是可以滑动的。 当我们滑动页面内弹出的弹窗、组件时,该页面也会跟着滚动,就会出现滚动弹窗内容时,页面内容也跟着滚动,这就是滚动穿透。 在PC端我们常通过给弹出弹窗的页面的body添加 overflow: hidden ,隐藏未显示的内容,

    2024年02月10日
    浏览(32)
  • scrollTop与offsetTop解决小分辨率区域块向上滚动效果效果,结合animation与@keyframes实现标题左右闪动更换颜色效果。

    scrollTop 是一个属性,它表示元素的滚动内容垂直滚动条的位置。对于可滚动元素, scrollTop 属性返回垂直滚动条滚动的像素数,即元素顶部被隐藏的像素数。  offsetTop 是一个属性,用于获取一个元素相对于其父元素的垂直偏移量(距离)。具体来说,返回的是一个元素的顶部

    2024年02月02日
    浏览(34)
  • 【uniapp】禁止遮罩层下的页面滚动解决办法

    不少朋友在日常工作中都会遇到需要自定义弹窗的时候,当开启弹窗后,却发现存在弹窗下的页面依旧可以被触发滚动的问题,以下是相关的解决方法。 根据是否打开的弹窗状态,对最外层 view 设置 height 和 overflow: 这个方法通过对页面设置高度来限制底层页面滚动的问题,

    2024年02月07日
    浏览(32)
  • vue页面设置滚动失败的解决方案(scrollTop一直为0)

    背景 希望页面能跳转到 某一位置用到了scrollTop属性。可是发现给某个div设置该属性后,一致为0。找了很多方案,但不都适合自己,或者说不知道是否适合。 怎么看我这个方法适不适合你 你可以尝试打印滚动条的位置,页面滚动后,再次打印滚动条的位置,如果一直为0的话,那我

    2024年02月04日
    浏览(64)
  • uniapp 小程序端使用uni-popup组件时,页面用了scroll-view滚动组件,uni-popup组件也使用了scroll-view滚动出现组件滚动导致页面也滚动的解决方案

    在 uni-popup上给一个禁止滚动 @touchmove.stop.prevent=\\\"\\\" 和一个样式height: 100vh;    

    2024年02月10日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包