仿米家右上角点击加号弹出菜单uniapp

admin 104 0
该功能仿照米家APP设计,在页面右上角设置悬浮加号按钮,点击后弹出包含多个功能选项的菜单,基于uniapp开发,支持iOS、Android等多端适配,通过CSS动画实现菜单展开收起效果,结合事件绑定处理选项点击逻辑,样式采用圆角、阴影等细节设计,提升用户体验,适用于需快速触发多功能的场景。

Uniapp实现仿米家右上角悬浮菜单交互效果

在移动端应用设计中,简洁高效的交互体验对提升用户留存率至关重要,小米米家APP的右上角悬浮菜单(点击加号按钮后菜单项以圆形扩散动画展开)因其直观的操作逻辑和流畅的视觉效果,已成为众多产品效仿的经典案例,本文将基于Uniapp框架,从组件拆解、动画实现到跨平台适配,完整拆解这一交互效果的实现方案。

效果概述与实现思路

目标效果

点击页面右上角固定位置的加号按钮,触发菜单展开动画:菜单项以按钮中心为圆心呈圆形扩散排列,支持点击菜单项执行对应操作;点击遮罩层或再次点击加号按钮可收起菜单,同时伴随反向动画效果。

实现思路

  • 组件化拆分:将悬浮菜单拆分为"固定按钮"和"动态菜单"两个独立组件,通过状态变量控制显隐逻辑
  • 布局方案:采用fixed定位实现按钮固定,菜单项使用绝对定位配合三角函数计算扩散位置
  • 交互逻辑:通过v-show指令控制菜单显示,结合事件冒泡处理遮罩层点击和菜单项点击
  • 动画实现:使用CSS transition实现位移动画,结合opacity渐变实现淡入淡出效果
  • 跨平台适配:针对不同平台特性使用条件编译,优化点击区域和动画表现

详细实现步骤

创建基础页面结构

在Uniapp页面中实现悬浮菜单的基础布局,以`index.vue`为例:

<template>
  <view class="container">
    <!-- 页面主体内容 -->
    <view class="content">
      <text>这是页面主体内容区域</text>
    </view>
    <!-- 右上角悬浮按钮 -->
    <view class="fab-btn" @click="toggleMenu">
      <text class="plus-icon">+</text>
    </view>
    <!-- 弹出菜单容器 -->
    <view class="menu-wrapper" v-show="isMenuShow" @click="closeMenu">
      <!-- 遮罩层 -->
      <view class="menu-mask"></view>
      <!-- 菜单项列表 -->
      <view class="menu-list">
        <view 
          class="menu-item" 
          v-for="(item, index) in menuItems" 
          :key="index"
          :style="getItemStyle(index)"
          @click.stop="handleItemClick(item)"
        >
          <image class="item-icon" :src="item.icon" mode="aspectFit"></image>
          <text class="item-text">{{item.text}}</text>
        </view>
      </view>
    </view>
  </view>
</template>

定义状态与数据

在`script`部分定义菜单数据和控制变量:

<script>
export default {
  data() {
    return {
      isMenuShow: false, // 菜单显示状态
      menuItems: [
        { icon: '/static/icons/scan.png', text: '扫码', action: 'scan' },
        { icon: '/static/icons/album.png', text: '相册', action: 'album' },
        { icon: '/static/icons/file.png', text: '文件', action: 'file' },
        { icon: '/static/icons/share.png', text: '分享', action: 'share' }
      ]
    }
  },
  methods: {
    // 切换菜单显示/隐藏
    toggleMenu() {
      this.isMenuShow = !this.isMenuShow;
      if (this.isMenuShow) {
        this.$nextTick(() => {
          this.animateMenuItems(); // 初始化菜单项动画
        });
      }
    },
    // 关闭菜单(点击遮罩层)
    closeMenu() {
      this.isMenuShow = false;
    },
    // 处理菜单项点击
    handleItemClick(item) {
      console.log('执行操作:', item.action);
      // 实际业务逻辑(如页面跳转、API调用等)
      this.closeMenu();
    },
    // 计算菜单项位置(圆形扩散)
    getItemStyle(index) {
      const totalItems = this.menuItems.length;
      const angleStep = (2 * Math.PI) / totalItems;
      const radius = 100; // 扩散半径(rpx)
      const angle = angleStep * index;
      // 计算x,y坐标(转换为rpx单位)
      const x = Math.cos(angle) * radius;
      const y = Math.sin(angle) * radius;
      return {
        transform: `translate(${x}rpx, ${y}rpx)`,
        opacity: 0,
        transition: 'all 0.3s ease'
      };
    },
    // 初始化菜单项动画
    animateMenuItems() {
      this.$nextTick(() => {
        const menuItems = document.querySelectorAll('.menu-item');
        menuItems.forEach((item, index) => {
          setTimeout(() => {
            item.style.opacity = 1;
          }, index * 50); // 错开动画时间
        });
      });
    }
  }
}
</script>

样式设计与动画实现

在`style`部分实现完整样式和动画效果:

<style>
.container {
  position: relative;
  width: 100%;
  min-height: 100vh;
  background-color: #f8f8f8;
}
.content {
  padding: 40rpx;
  text-align: center;
}
/* 悬浮按钮样式 */
.fab-btn {
  position: fixed;
  top: 40rpx;
  right: 40rpx;
  width: 100rpx;
  height: 100rpx;
  background: linear-gradient(135deg, #ff6700, #ff9800);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 8rpx 16rpx rgba(255, 103, 0, 0.3);
  z-index: 1000;
  transition: transform 0.3s ease;
}
.fab-btn:active {
  transform: scale(0.95);
}
.plus-icon {
  color: #ffffff;
  font-size: 60rpx;
  font-weight: bold;
}
/* 菜单容器 */
.menu-wrapper {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 999;
}
/* 遮罩层 */
.menu-mask {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.3);
  transition: opacity 0.3s ease;
}
/* 菜单项列表 */
.menu-list {
  position: absolute;
  top: 40rpx;
  right: 40rpx;
  width: 200rpx;
  height: 200rpx;
  display: flex;
  align-items: center;
  justify-content: center;
}
/* 单个菜单项 */
.menu

标签: #米家菜单 #右上弹窗