Uniapp 实现微信小程序滑动面板功能详解

文章目录


前言

Uniapp 实现微信小程序滑动面板功能详解


一、功能概述

滑动面板是移动端常见的交互组件,通常用于在页面底部展开内容面板。本文将介绍如何使用 Uniapp 开发一个支持手势滑动的底部面板组件,实现以下核心功能:

触摸滑动调整面板高度

边界限制

与地图组件的层级适配

二、实现思路

使用 Uniapp 框架实现跨平台兼容

通过 CSS transform 实现动画效果

基于微信小程序触摸事件体系

结合选择器 API 获取元素尺寸

触摸事件监听:捕获 touchstart/touchmove/touchend 事件

滑动距离计算:通过 clientY 坐标差值计算滑动距离

边界限制:确保面板在允许的高度范围内滑动

弹性动画:使用 CSS transition 实现平滑过渡

层级管理:通过 z-index 控制与其他组件的层级关系

三、代码实现

javascript 复制代码
<template>
  <view
    class="slider-panel"
    @touchstart="handleTouchStart"
    @touchmove.stop.prevent="handleTouchMove"
    @touchend="handleTouchEnd"
    :style="{
      'min-height': `${initialPosition}px`,
      transform: `translateY(${translateY}px)`
    }"
  >
    <view class="slider-panel-handle"></view>
    <view class="slider-panel-content">
      <slot></slot>
    </view>
  </view>
</template>
<script>
export default {
  name: 'SliderPanel',
  props: {
    initialPosition: {
      type: Number,
      default: 100
    },
    deltaYThreshold: {
      type: Number,
      default: 100
    }
  },
  data() {
    return {
      isDragging: false,
      startY: 0,
      translateY: 0,
      panelHeight: 0,
      panelInitialShowHeight: 0
    }
  },
  async mounted() {
    const { height } = await this.getSelectorRect('.slider-panel-content')
    this.panelHeight = height
    if (this.initialPosition > this.panelHeight) {
      this.panelInitialShowHeight = this.panelHeight
    } else {
      this.panelInitialShowHeight = height - this.initialPosition
      this.translateY = this.panelInitialShowHeight
    }
  },
  methods: {
    getSelectorRect(selector) {
      const query = wx.createSelectorQuery().in(this)
      return new Promise((resolve) => {
        query
          .select(selector)
          .boundingClientRect((rect) => {
            resolve(rect)
          })
          .exec()
      })
    },
    handleTouchStart(event) {
      const { clientY } = event.touches[0]
      this.isDragging = true
      this.startY = clientY
    },
    handleTouchMove(event) {
      if (this.isDragging) {
        const { clientY } = event.touches[0]
        const deltaY = clientY - this.startY
        this.startY = clientY
        this.translateY += deltaY
        if (this.translateY < 0) {
          this.translateY = 0
        }
        if (this.translateY > this.panelInitialShowHeight) {
          this.translateY = this.panelInitialShowHeight
        }
      }
    },
    handleTouchEnd() {
      this.isDragging = false
    }
  }
}
</script>

<style scoped lang="scss">
.slider-panel {
  position: fixed;
  width: 100%;
  box-sizing: border-box;
  left: 0;
  bottom: 0;
  background: #fff;
  padding: 20rpx;
  border-radius: 24px 24px 0 0;
  box-shadow: 0 -4px 12px rgba(0, 0, 0, 0.1);
  z-index: 30;
  will-change: transform;
  .slider-panel-handle {
    width: 60rpx;
    height: 6rpx;
    border-radius: 3rpx;
    background: #f0f0f0;
    margin: 16rpx auto 24rpx;
  }
}
</style>
javascript 复制代码
<template>
  <view class="container">
    <map style="width: 100%; height: 100%" :enable-scroll="false"></map>
    <slider-panel>
      <view v-for="item in 20" :key="item">
        <view class="item">
          {{ item }}
        </view>
      </view>
    </slider-panel>
  </view>
</template>
<script>
import SliderPanel from '@/components/sliderPanel'
export default {
  components: {
    SliderPanel
  },
  data() {
    return {}
  },
  methods: {}
}
</script>

<style lang="scss">
page {
  height: 100%;
  width: 100%;
}
</style>

<style scoped lang="scss">
.container {
  position: relative;
  height: 100%;
  width: 100%;
  overflow: hidden;
  .item {
    display: flex;
    align-items: center;
    justify-content: center;
    border-bottom: 1px solid #ccc;
    height: 80rpx;
  }
}
</style>

总结

通过 Uniapp 开发滑动面板组件,可以有效实现跨平台兼容。核心在于:

正确处理触摸事件流

合理使用 CSS 动画

精确控制滑动边界

做好性能优化

相关推荐
计算机毕设定制辅导-无忧学长21 分钟前
《校园食堂在线订餐小程序的设计与实现》
java·vue.js·spring boot·微信小程序·uniapp·校园食堂在线订餐小程序
咖啡无伴侣2 小时前
1. 别再手动改代码格式了!Vue3 项目工程化规范搭建实战
vue.js·架构
知野小兔5 小时前
Vuex和Pinia状态管理
vue.js
VX_bysjlw9856 小时前
数码设备销售网站设计与实现39138-计算机毕设原创(免费领源码+带部署教程)
java·vue.js·spring boot·mysql·tomcat·mybatis·idea
whi10 小时前
一个小工具,解决了一个困扰 Vue 开发者多年的类型检查难题
vue.js·typescript
郑州光合科技余经理10 小时前
本地生活平台搭建:跨业态用户标识怎么贯通
java·开发语言·前端·后端·uni-app·php·ai编程
xcs194051 天前
前端 vue 的前端页面debugger 进不去
前端·javascript·vue.js
雪芽蓝域zzs1 天前
第 5 节:Marker 点击弹出 InfoWindow 信息窗口
vue.js
大包子1 天前
structuredClone vs lodash.cloneDeep:核心差异与选型指南
javascript·vue.js
雪芽蓝域zzs1 天前
第 3 节:地图点击事件,点击获取经纬度
vue.js