uniapp仿抖音评论区popup对话框实现(多端兼容)

一、先看一下弹框实现效果

二、对话框跟随手势下拉实现

从上面的实现效果图中可以发现,弹窗会跟随手势向下移动进行同步移动,想要实现这个功能,需要获取我们的手势向下的移动距离,然后再把这个距离设置给弹窗,作为向下隐藏的距离。

即:弹窗向下移动的距离 = 手势向下移动的距离

1.手势向下移动距离的计算公式

手势向下移动的距离 = 手势当前向下移动到的Y坐标 - 手势开始移动的Y坐标

uniapp中提供了可以兼容多端的监听页面上元素的触摸方法:

1.手指开始触摸元素

element.touchstart:element.touchstart(options: Object): Promise<void>

2.手指触摸元素后移动。

element.touchmove:element.touchmove(options: Object): Promise<void>

3.手指结束触摸元素

element.touchend:element.touchend(options: Object): Promise<void>

options 字段定义如下:

字段 类型 必填 默认值 说明
touches array - 触摸事件,当前停留在屏幕中的触摸点信息的数组
changedTouches array - 触摸事件,当前变化的触摸点信息的数组

2.获取手势向下移动的距离

下面将使用选项api 来实现相应功能,目的也是为了同时兼容 vue2vue3版本。

js 复制代码
<template>
<uni-popup ref="popup" type="bottom">
    <view class="content"
        @touchstart="touchstart" 
        @touchmove="touchmove"
    >
      ...
    </view>
</uni-popup>
</template>

<script>
  export default {
    data() {
      return {
        // 手势向下移动距离
        moveDistance: 0
      }
    },
    methods: {
      // 开始触摸元素
      touchstart(e) {
        this.startY = e.changedTouches[0].clientY;
        this.startIme = Date.now()
        this.toumoveTime = Date.now()
      },
      // 触摸元素后移动
      touchmove(e) {
        const clientY = e.changedTouches[0].clientY;
        // 忽略上划
        if (clientY < this.startY) {
          return
        }
        // 下滑,计算手势移动距离
        this.moveDistance = clientY - this.startY
      },
    }
  }
</script>

通过e.changedTouches[0].clientY可获取当前屏幕触摸的Y坐标。

3.弹框向下隐藏同步手指向下触摸移动距离

可以通过css属性transform来设置弹窗向下移动距离,来达到隐藏弹窗的效果。

transform: `translateY(${this.moveDistance}px)`

js 复制代码
<script>
  export default {
    data() {
      return {
        // 手势向下移动距离
        moveDistance: 0
      }
    },
    computed: {
      contentStyle() {
        return {
          transform: `translateY(${this.moveDistance}px)`,
        }
      }
    },
  }
</script>

<template>
<uni-popup ref="popup" type="bottom">
    <view class="content"
        ...
       :style="contentStyle"
    >
      ...
    </view>
</uni-popup>
</template>

三、关闭弹窗时机

上面已经完成了弹窗的随手势进行移动,下面将确定弹窗隐藏的时机,即满足条件调用this.$refs.popup.close()方法关闭弹窗。经过我的一番测试,发现抖音 的评论区弹窗具有两种关闭时机,分别为距离底部一定距离时手指开始、移动、结束触摸元素这三个事件快速完成时都会关闭弹窗。

关闭弹窗我们可以在元素上绑定touchend方法,当触发触摸结束方法时进行相关计算。

1.计算距离底部距离

距离底部距离 = 窗口高度 - 当前手指触摸结束的Y坐标

js 复制代码
touchend(e) {
    // 触摸结束Y坐标
    const clientY = e.changedTouches[0].clientY;
    // 获取窗口高度
    const { windowHeight } = uni.getSystemInfoSync();
    // 距离底部距离
    const distance = windowHeight - clientY
}

2.计算手势完成时间

js 复制代码
touchstart(e) {
    this.startIme = Date.now()
},
touchend(e) {
    // 手势完成时间(毫秒)
    const toumoveTime = Date.now() - this.startIme
},

3.根据计算值,完成弹窗关闭逻辑

js 复制代码
touchend(e) {
    // 触摸结束Y坐标
    const clientY = e.changedTouches[0].clientY;
    // 获取窗口高度
    const { windowHeight } = uni.getSystemInfoSync();
    // 距离底部距离
    const distance = windowHeight - clientY

    // 滑动时间(毫秒),小于某个时间则自动close
    const toumoveTime = Date.now() - this.startIme

    // 必须触发了touchmove方法
    if (this.moveDistance > 0 && (distance < this.bottomCloseValue || toumoveTime < this.moveCloseTime)) {
      this.close();
    } else {
      this.moveDistance = 0;
    }
},

当结束触摸时,如果满足设置的距离设置的触摸完成时间,则关闭弹窗;反之,则复原弹窗。

四、打开全屏

打开全屏主要是计算可用视口高度,并把弹窗内容高度设置为可用视口高度。

js 复制代码
toggleFullScreen() {
    if (this.isFullScrren) {
      // 关闭全屏,高度设为内容高度
      this.height = this.contentHeight
    } else {
    // 开启全屏,设为视口高度
      this.height = this.windowHeight
    }
    this.isFullScrren = !this.isFullScrren
},

同时兼容ios微信小程序和App端顶部和底部安全区域适配

适配iphone手机顶部和底部安全区域

js 复制代码
const {
    safeArea,
    windowHeight,
    screenHeight,
    osName
} = uni.getSystemInfoSync();
// 适配顶部和底部安全区域, safeArea.height安全区域的高度,单位逻辑像素
const safeWindowHeight = windowHeight - (screenHeight - safeArea.bottom)
// 打开全屏的高度
this.windowHeight = safeWindowHeight

适配Android手机app端顶部和底部安全区域

js 复制代码
// #ifdef APP-PLUS
const {
    windowHeight,
    osName
} = uni.getSystemInfoSync();
if (osName === 'ios') {
    // ios没设备
} else {
    // android
    打开全屏的高度
    this.windowHeight = windowHeight
}

五、总结

以上实现主要有三部分内容:

1.弹窗跟随手势向下移动。

2.手势距离底部一定距离或者手势移动足够快关闭弹窗。

3.通过uni.getSystemInfoSync()获取设备信息计算弹窗的全屏高度,兼容不同设备类型。

去体验插件:uniapp插件市场

相关推荐
TeleostNaCl1 小时前
解决 Chrome 无法访问网页但无痕模式下可以访问该网页 的问题
前端·网络·chrome·windows·经验分享
前端大卫3 小时前
为什么 React 中的 key 不能用索引?
前端
你的人类朋友3 小时前
【Node】手动归还主线程控制权:解决 Node.js 阻塞的一个思路
前端·后端·node.js
小李小李不讲道理5 小时前
「Ant Design 组件库探索」五:Tabs组件
前端·react.js·ant design
毕设十刻5 小时前
基于Vue的学分预警系统98k51(程序 + 源码 + 数据库 + 调试部署 + 开发环境配置),配套论文文档字数达万字以上,文末可获取,系统界面展示置于文末
前端·数据库·vue.js
mapbar_front5 小时前
在职场生存中如何做个不好惹的人
前端
牧杉-惊蛰6 小时前
纯flex布局来写瀑布流
前端·javascript·css
一袋米扛几楼987 小时前
【软件安全】什么是XSS(Cross-Site Scripting,跨站脚本)?
前端·安全·xss
向上的车轮7 小时前
Actix Web适合什么类型的Web应用?可以部署 Java 或 .NET 的应用程序?
java·前端·rust·.net
XiaoYu20027 小时前
第1章 核心竞争力和职业规划
前端·面试·程序员