移动端点击穿透、滚动穿透解决方案

4,658 阅读3分钟

「这是我参与2022首次更文挑战的第7天,活动详情查看:2022首次更文挑战」。

前言

前段时间开发了一个H5的活动专题页面,在这个H5专题页中有一个需求是点击按钮弹框显示活动详情。这个需求看似平平无奇。当中却蕴含着一些我们值得学习的知识点。点击穿透与滑动穿透

什么是点击穿透、滑动穿透

在这之前,我们必须先了解下移动端300ms延迟触发。为了实现浏览器双击缩放效果,浏览器需要鉴别出用户是否点击了屏幕两次。

由于移动端设备没有鼠标。因此用户的点击事件在移动端会被拆分为如下过程touchstart -> touchmove -> touchend -> click 当用户点击屏幕时,浏览器会分别监听这几个事件。

当touched事件触发之后。浏览器会在此做一个300ms延迟触发。这个300ms的延迟被用来鉴别用户是否双击了屏幕。

也正是因为这个延迟,导致了移动端的点击穿透

下面用一个例子来展示点击穿透:

//test.vue
<div v-show="showOverlay" class="overlay" >
  <div class="rule-box">
    <div class="form-box">
      <div class="form-box-title">{{ title }}</div>
      <div class="rules-box" v-html="filterRulesText">
      </div>
    </div>
    <div>
      <img @click="showOverlay =false" class="close-btn" src="../images/close.png" alt="">
    </div>
  </div>
</div>
</template>
<script>
export default { 
  name:'test',
  props: {
    rulesText: {
      type: String,
      default: ''
       },
  data(){
   return {
     title:'查看活动详情'
     showOverlay:false
    }
  },
computed: {
  filterRulesText() {
    const str = this.rulesText
    const newStr = str.replace(/\r\n|\n|\r/g, '<br/>')
    // console.log(newStr)
    return newStr
  },
  methods:{
   init(){
    this.showOverlay = true
   }
  }
}
</script>
//app.vue中
<template>
<div>
<Button @click="$refs.openDialog.init()">点击查看活动详情</Button>
<Test ref="openDialog"></Test>
</div>
<script>
import Test from '@/components/Test'
export default {
 name:'app',
 components:{Test}
}

image.png

大致效果如上图:当我点击图中的close图片时,移动端整个屏幕的遮罩以及详情都会被隐藏掉,该组件也隐藏在了dom中。

由于浏览器的300ms延迟导致本应该作用在test组件中的click事件被穿透到了父组件的app中。

这就是点击穿透~~~ 滑动传统与点击穿透是一样的原理。

点击穿透解决方法

  • 阻止浏览器的默认事件 e.preventDefault() 在vue中使用@click.stop即可组件默认事件。 但并不是所有的浏览器都支持
  • 禁止浏览器进行缩放也可以解决300ms延迟的问题。
  • 增加弹框过渡动画
  • 使用fastclick

滑动穿透解决方法

H5项目内容较多时,我们会增加滚动条使得body当中的内容可以滑动。

当用户点击查看详情时:如果详情的内容较少。那么我们的弹框里面的内容则不需要滑动

当你滑动弹框以外的内容时你会发现body中的内容竟然滑动了。这也是300ms延迟造成的。此时的解决方案很简单
我们只需要在vue使用事件修饰符就可以。

在遮罩层的div中添加@touchmove.prevent

<div v-show="showOverlay" class="overlay"  @touchmove.prevent>

当详情页的内容较多时。由于文字太多 我们需要用到滚动条。此时我们会给弹框详情加上overflow:scroll 添加后。你会发现 弹框中的滚动条失效了。 并不会滚动。

之所以如此 是因为我们之前使用@touchmove.prevent阻止掉了body中的滚动条事件,但是该事件也同样作用到了弹框中。因此该方法不可用。

那么怎么解决呢?给body添加滚动隐藏的样式。当vue中showOverlay的值发生改变时修改body的样式:

//代码忽略。。。。
watch:{
  showOverlay(val){
     this.styleChange(val)
    }
 
  },
methods:{
 styleChange(val){
   let body = document.body
  
  //val 为true时 添加overflow为hidden
  if(val){
      body.style.overflow = 'hidden'
  }else{
    body.style.overflow ='scroll'
  }
 }
}

这样就能解决掉滑动穿透的问题。 当然,如上代码你也可以封装成一个自定义指令~~~~~~

最后

文章若有不足之处,还请大家批评指出。

感谢您观看此篇文章 希望能给个👍评论收藏三连!你的点赞就是我写作的动力。