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插件市场

相关推荐
mldong7 小时前
你的 Vue3 项目也能有钉钉同款审批流设计器:npm 装包,10 分钟画出第一条审批流
前端·vue.js
2分钟速写快排7 小时前
什么是 RAG?如何用 RAG 实现一个用户记忆?
前端·后端·ai编程
passerby60618 小时前
如何自己造一个时间处理库
前端·javascript·github
走到天涯海角9 小时前
react里面的长列表渲染优化
前端·react.js·前端框架
小羊没烦恼!9 小时前
Hello Web API系列教程——Web API与国际化
java·服务器·前端·javascript·php
北岛贰9 小时前
迷茫焦虑期,我做了一个带支付带官网的 AI 聊天虚拟恋人 App
前端·人工智能·后端
mayaairi11 小时前
Vue2 组件通讯(三):全局事件总线、PubSub、插槽与组件实例属性
前端·javascript·vue.js
kyriewen11 小时前
面试官问我:AI 都能写代码了,前端凭什么还值 25K
前端·javascript·人工智能
风骏时光牛马12 小时前
AI源码分析:拆解模型底层实现逻辑
前端
BillKu12 小时前
全局样式变量:CSS 自定义属性(--border-color)和SCSS 变量($border-color)的说明
javascript·css·scss