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 动画

精确控制滑动边界

做好性能优化

相关推荐
aklry21 分钟前
uniapp三步完成生成一维码图片
uni-app
幽络源小助理10 小时前
SpringBoot基于Mysql的商业辅助决策系统设计与实现
java·vue.js·spring boot·后端·mysql·spring
汤姆yu10 小时前
基于微信小程序的学校招生系统
微信小程序·小程序·招生小程序
雪芽蓝域zzs10 小时前
uniapp 国密sm2加密
uni-app
鱼樱前端12 小时前
今天介绍下最新更新的Vite7
前端·vue.js
炒毛豆14 小时前
vue3.4中的v-model的用法~
前端·vue.js
阳火锅15 小时前
都2025年了,来看看前端如何给刘亦菲加个水印吧!
前端·vue.js·面试
夕水16 小时前
ew-vue-component:Vue 3 动态组件渲染解决方案的使用介绍
前端·vue.js
我麻烦大了16 小时前
实现一个简单的Vue响应式
前端·vue.js
aklry17 小时前
uniapp三步完成一维码的生成
前端·vue.js