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

精确控制滑动边界

做好性能优化

相关推荐
咕噜咕噜啦啦1 小时前
Vue3响应式开发
前端·javascript·vue.js
qq8406122338 小时前
Nodejs+vue基于elasticsearch的高校科研期刊信息管理系统_mb8od
前端·vue.js·elasticsearch
程序员林北北13 小时前
【前端进阶之旅】Svelte:编译即框架,让前端开发回归简洁
前端·javascript·vue.js·react.js·html5
pas13615 小时前
46-mini-vue 实现编译 template 为 render 函数
前端·javascript·vue.js
左夕16 小时前
深度解析vue的生命周期
vue.js
随逸17716 小时前
《彻底解决CSS冲突!模块化CSS实战指南》
vue.js·react.js
筱筱°16 小时前
创建一个基于 Vue 的微前端项目
vue.js·微前端
爱看书的小沐19 小时前
【小沐杂货铺】基于Three.js渲染三维无人机Drone(WebGL / vue / react )
javascript·vue.js·react.js·无人机·webgl·three.js·drone
ShenJLLL1 天前
vue部分知识点.
前端·javascript·vue.js·前端框架
码云数智-大飞1 天前
自助建站系统哪个好?快速建站哪个平台好
微信小程序