ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

滚动穿透与滚动溢出

2022-06-08 12:02:02  阅读:192  来源: 互联网

标签:popup 滚动 100% 50% amd 穿透 top 溢出 left


滚动穿透

问题描述:

在移动端开发弹框时(小程序也会出现),当弹框下的页面超过一屏时它下面的内容也会跟着一起滑动,看起来好像事件穿透到了下面的DOM元素一样

问题原因:

通过事件的表象,可以推测是文档的滚动事件被触发了,那我们就禁用滚动事件就好办了。

案例伪代码:

解决方案A✅ e.preventDefault()

小程序——脚本语法,通过e.preventDefault()阻止元素的touch-move事件。(H5同理,监听touch-move事件,阻止其touch-move事件)

<view
      :class="['asian-popup', classNames]"
      :style="{ 'z-index': zIndex }"
      @touchmove="utils.disableScrollEvent"
      v-if="visible"
      >
  <view class="asian-popup-mask" />
  <view :class="['asian-popup-content', 'asian-popup-' + position]">
      <slot />
  </view>
  </view>
function disableScrollEvent(event) {
  event.preventDefault();
}

function enableScrollEvent(event) {
  event.stopPropagation();
}

export default {
  disableScrollEvent,
  enableScrollEvent,
};

 

解决方案B✅ (touch-action)

默认情况下,平移(滚动)和缩放手势由浏览器专门处理,但是可以通过 CSS 特性 touch-action 来改变触摸手势的行为。摘取几个 touch-action 的值如下。

描述

auto

启用浏览器处理所有平移和缩放手势。

none

禁用浏览器处理所有平移和缩放手势。

manipulation

启用平移和缩放手势,但禁用其他非标准手势,例如双击缩放。

pinch-zoom

启用页面的多指平移和缩放。

于是在 popup 元素上设置该属性,禁用元素(及其不可滚动的后代)上的所有手势就可以解决该问题了。

 <view
    :class="['asian-popup', classNames]"
    :style="{ 'z-index': zIndex,touchAction:'none' }"
    v-if="visible"
  >
    <view class="asian-popup-mask" />
    <view :class="['asian-popup-content', 'asian-popup-' + position]">

        <slot />
    </view>
  </view>

 

滚动溢出

问题描述:

弹窗内也含有滚动元素,在滚动元素滚到底部或顶部时,再往下或往上滚动,也会触发页面的滚动,这种现象称之为滚动链

解决方案-A✅ (disable-lower/upper-scroll)

支付宝小程序官方提供的 scroll-view 组件,使用 disable-lower-scroll 与 disable-upper-scroll 属性可以解决问题.

背后的原理是,当组件滚动到底部或顶部时,通过调用 event.preventDefault 阻止了所有滚动,从而页面滚动也不会触发了,而在滚动之间则不做处理。

<view
      :class="['asian-popup', classNames]"
      :style="{ 'z-index': zIndex }"
      @touchmove="utils.disableScrollEvent"
      v-if="visible"
      >
  <view class="asian-popup-mask" />
  <view :class="['asian-popup-content', 'asian-popup-' + position]">
    <scroll-view
                 @touchmove="utils.enableScrollEvent"
                 :style="{maxHeight:contentMaxHeight}"
                 :scroll-y="true"
                 disable-lower-scroll="out-of-bounds"
                 disable-upper-scroll="out-of-bounds"
                 >
      <slot />
  </scroll-view>
  </view>
  </view>

 

解决方案完整 Demo

小程序使用sjs

<template>
<view
      :class="['asian-popup', classNames]"
      :style="{ 'z-index': zIndex }"
      @touchmove="utils.disableScrollEvent"
      v-if="visible"
      >
  <view class="asian-popup-mask" />
  <view :class="['asian-popup-content', 'asian-popup-' + position]">
    <scroll-view
                 @touchmove="utils.enableScrollEvent"
                 :style="{maxHeight:contentMaxHeight}"
                 :scroll-y="true"
                 disable-lower-scroll="out-of-bounds"
                 disable-upper-scroll="out-of-bounds"
                 >
      <slot />
  </scroll-view>
  </view>
  </view>
</template>
<script module="utils" lang="sjs" src="./index.sjs"></script>
<script lang="ts">
  import { Component, Vue, Prop } from 'vue-property-decorator';
  @Component({
    components: {},
  })
  export default class Popup extends Vue {
    @Prop({ type: String, default: '' }) private classNames;
    @Prop({ type: String, default: 'center' }) private position;
    @Prop({ type: Number, default: 998 }) private zIndex;
    @Prop({ type: Boolean, default: true }) private animations;
    @Prop({ type: Number, default: 300 }) private duration;
    @Prop({ type: Boolean, default: true }) private visible;
    @Prop({ type: String, default: '500rpx' }) private contentMaxHeight
  }
</script>

<style lang="less">
  @popupPrefix: asian-popup;
  .@{popupPrefix} {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 998;
    &-mask {
      width: 100%;
      height: 100%;
      background-color: rgba(0, 0, 0, 0.55);
    }
    &-content {
      position: fixed;
      background-color: #fff;
      z-index: 2;
      padding: 24rpx;
      display: flex;
      flex-direction: column;
      height: auto;
    }
    &-top {
      top: 0;
      left: 0;
      right: 0;
      animation-name: amd-popup-top;
      border-radius: 0 0 8rpx 8rpx;
    }
    &-right {
      top: 0;
      right: 0;
      bottom: 0;
      animation-name: amd-popup-right;
      width: 500rpx;
    }
    &-bottom {
      left: 0;
      right: 0;
      bottom: 0;
      animation-name: amd-popup-bottom;
      border-radius: 8rpx 8rpx 0 0;
    }
    &-left {
      top: 0;
      left: 0;
      bottom: 0;
      animation-name: amd-popup-left;
      width: 500rpx;
    }
    &-center {
      min-width: 500rpx;
      top: 50%;
      left: 50%;
      transform: translate3d(-50%, -50%, 0);
      animation-name: amd-popup-center;
      border-radius: 8rpx;
    }
  }
  @keyframes amd-popup-top {
    0% {
      top: -100%;
    }
    100% {
      top: 0;
    }
  }
  
  @keyframes amd-popup-bottom {
    0% {
      bottom: -100%;
    }
    100% {
      bottom: 0;
    }
  }
  
  @keyframes amd-popup-left {
    0% {
      left: -100%;
    }
    100% {
      left: 0;
    }
  }
  
  @keyframes amd-popup-right {
    0% {
      right: -100%;
    }
    100% {
      right: 0;
    }
  }
  
  @keyframes amd-popup-center {
    0% {
      transform: translate3d(-50%, -50%, 0) scale(0.1);
      opacity: 0;
    }
    70% {
      transform: translate3d(-50%, -50%, 0) scale(1.2);
      opacity: 1;
    }
    80% {
      transform: translate3d(-50%, -50%, 0) scale(0.95);
    }
    85% {
      transform: translate3d(-50%, -50%, 0) scale(1.1);
      opacity: 0.9;
    }
    95% {
      transform: translate3d(-50%, -50%, 0) scale(0.97);
      opacity: 1;
    }
    100% {
      transform: translate3d(-50%, -50%, 0) scale(1);
    }
  }
</style>
function disableScrollEvent(event) {
  event.preventDefault();
}

function enableScrollEvent(event) {
  event.stopPropagation();
}

export default {
  disableScrollEvent,
  enableScrollEvent,
};

 

使用touch-action: none

<template>
  <view
    :class="['asian-popup', classNames]"
    :style="{ 'z-index': zIndex }"
    v-if="visible"
  >
    <view class="asian-popup-mask" />
    <view :class="['asian-popup-content', 'asian-popup-' + position]">
      <scroll-view
        :style="{maxHeight:contentMaxHeight}"
        :scroll-y="true"
        disable-lower-scroll="out-of-bounds"
        disable-upper-scroll="out-of-bounds"
      >
        <slot />
      </scroll-view>
    </view>
  </view>
</template>

<script lang="ts">
import { Component, Vue, Prop } from 'vue-property-decorator';
@Component({
  components: {},
})
export default class Popup extends Vue {
  @Prop({ type: String, default: '' }) private classNames;
  @Prop({ type: String, default: 'center' }) private position;
  @Prop({ type: Number, default: 998 }) private zIndex;
  @Prop({ type: Boolean, default: true }) private animations;
  @Prop({ type: Number, default: 300 }) private duration;
  @Prop({ type: Boolean, default: true }) private visible;
  @Prop({ type: String, default: '500rpx' }) private contentMaxHeight
}
</script>

<style lang="less">
@popupPrefix: asian-popup;
.@{popupPrefix} {
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 998;
  touch-action: none;
  &-mask {
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.55);
  }
  &-content {
    position: fixed;
    background-color: #fff;
    z-index: 2;
    padding: 24rpx;
    display: flex;
    flex-direction: column;
    height: auto;
  }
  &-top {
    top: 0;
    left: 0;
    right: 0;
    animation-name: amd-popup-top;
    border-radius: 0 0 8rpx 8rpx;
  }
  &-right {
    top: 0;
    right: 0;
    bottom: 0;
    animation-name: amd-popup-right;
    width: 500rpx;
  }
  &-bottom {
    left: 0;
    right: 0;
    bottom: 0;
    animation-name: amd-popup-bottom;
    border-radius: 8rpx 8rpx 0 0;
  }
  &-left {
    top: 0;
    left: 0;
    bottom: 0;
    animation-name: amd-popup-left;
    width: 500rpx;
  }
  &-center {
    min-width: 500rpx;
    top: 50%;
    left: 50%;
    transform: translate3d(-50%, -50%, 0);
    animation-name: amd-popup-center;
    border-radius: 8rpx;
  }
}
@keyframes amd-popup-top {
  0% {
    top: -100%;
  }
  100% {
    top: 0;
  }
}

@keyframes amd-popup-bottom {
  0% {
    bottom: -100%;
  }
  100% {
    bottom: 0;
  }
}

@keyframes amd-popup-left {
  0% {
    left: -100%;
  }
  100% {
    left: 0;
  }
}

@keyframes amd-popup-right {
  0% {
    right: -100%;
  }
  100% {
    right: 0;
  }
}

@keyframes amd-popup-center {
  0% {
    transform: translate3d(-50%, -50%, 0) scale(0.1);
    opacity: 0;
  }
  70% {
    transform: translate3d(-50%, -50%, 0) scale(1.2);
    opacity: 1;
  }
  80% {
    transform: translate3d(-50%, -50%, 0) scale(0.95);
  }
  85% {
    transform: translate3d(-50%, -50%, 0) scale(1.1);
    opacity: 0.9;
  }
  95% {
    transform: translate3d(-50%, -50%, 0) scale(0.97);
    opacity: 1;
  }
  100% {
    transform: translate3d(-50%, -50%, 0) scale(1);
  }
}
</style>

 

标签:popup,滚动,100%,50%,amd,穿透,top,溢出,left
来源: https://www.cnblogs.com/lvlvlv/p/16355136.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有