• 滚动穿透与滚动溢出


    滚动穿透

    问题描述:

    在移动端开发弹框时(小程序也会出现),当弹框下的页面超过一屏时它下面的内容也会跟着一起滑动,看起来好像事件穿透到了下面的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 {
           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;
           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;
           500rpx;
        }
        &-center {
          min- 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 {
         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;
         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;
         500rpx;
      }
      &-center {
        min- 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>
  • 相关阅读:
    .NETCORE微服务架构--网关篇(Ocelot)
    Hangfire实战--添加DashBoard登录权限
    IIS发布-HTTP谓词限制访问
    基于Dapper的泛型Repository
    .Net Framework JWT验证
    .Net Framework swagger 进阶----头部参数
    .Net Framework下安装api swagger
    ErrorSet
    201907总结
    博客美化
  • 原文地址:https://www.cnblogs.com/lvlvlv/p/16355136.html
Copyright © 2020-2023  润新知