UniApp 实现自定义的侧边栏菜单组件
前言
在移动应用开发中,侧边栏(Drawer)菜单是提升导航效率和用户体验的重要组件。它不仅能容纳更多功能入口,还能让界面更简洁有序。随着鸿蒙(HarmonyOS)生态的壮大,开发者对多端适配和高性能交互提出了更高要求。本文将以 UniApp 为例,详细讲解如何开发一个美观、实用、适配鸿蒙的自定义侧边栏菜单组件。
一、需求与设计思路
1. 需求分析
- 支持左侧/右侧弹出
- 支持自定义菜单项、图标、跳转
- 支持遮罩点击关闭、滑动关闭
- 兼容鸿蒙平台,适配不同分辨率
- 组件化设计,便于复用和扩展
2. 设计思路
- 使用绝对定位和过渡动画实现侧边栏弹出/收起
- 菜单项通过 v-for 渲染,支持动态扩展
- 遮罩层点击或滑动手势关闭菜单
- 结合 CSS3 动画提升交互体验
- 适配鸿蒙平台的手势和安全区域
二、核心代码实现
1. 组件结构
<template>
<view>
<view class="drawer-mask" v-if="show" @click="close"></view>
<view
class="drawer"
:class="[side, { show }]"
:style="drawerStyle"
@touchstart="onTouchStart"
@touchmove="onTouchMove"
@touchend="onTouchEnd"
>
<view class="drawer-header">
<slot name="header">菜单</slot>
</view>
<view class="drawer-menu">
<view
v-for="item in menu"
:key="item.key"
class="drawer-item"
@click="onSelect(item)"
>
<image v-if="item.icon" :src="item.icon" class="icon" />
<text>{{ item.label }}</text>
</view>
</view>
<view class="drawer-footer">
<slot name="footer"></slot>
</view>
</view>
</view>
</template>
2. 脚本逻辑
<script>
export default {
name: 'SidebarDrawer',
props: {
show: { type: Boolean, default: false },
menu: { type: Array, default: () => [] },
side: { type: String, default: 'left' }, // left/right
width: { type: String, default: '70vw' },
},
data() {
return {
startX: 0,
deltaX: 0,
};
},
computed: {
drawerStyle() {
return `width: ${this.width};`;
},
},
methods: {
close() {
this.$emit('update:show', false);
},
onSelect(item) {
this.$emit('select', item);
this.close();
},
onTouchStart(e) {
this.startX = e.touches[0].clientX;
this.deltaX = 0;
},
onTouchMove(e) {
this.deltaX = e.touches[0].clientX - this.startX;
},
onTouchEnd() {
// 左侧菜单向左滑,右侧菜单向右滑关闭
if (
(this.side === 'left' && this.deltaX < -60) ||
(this.side === 'right' && this.deltaX > 60)
) {
this.close();
}
},
},
};
</script>
3. 样式设计
<style scoped>
.drawer-mask {
position: fixed;
left: 0; top: 0; right: 0; bottom: 0;
background: rgba(0,0,0,0.3);
z-index: 99;
animation: fadeIn 0.2s;
}
.drawer {
position: fixed;
top: 0; bottom: 0;
width: 70vw;
background: #fff;
z-index: 100;
box-shadow: 4rpx 0 32rpx rgba(0,0,0,0.08);
transition: transform 0.25s cubic-bezier(.4,0,.2,1);
will-change: transform;
padding-bottom: env(safe-area-inset-bottom);
display: flex;
flex-direction: column;
}
.drawer.left {
left: 0;
transform: translateX(-100%);
}
.drawer.right {
right: 0;
transform: translateX(100%);
}
.drawer.show.left {
transform: translateX(0);
}
.drawer.show.right {
transform: translateX(0);
}
.drawer-header {
padding: 48rpx 32rpx 24rpx 32rpx;
font-size: 32rpx;
font-weight: bold;
color: #222;
border-bottom: 1rpx solid #f0f0f0;
}
.drawer-menu {
flex: 1;
padding: 24rpx 0;
overflow-y: auto;
}
.drawer-item {
display: flex;
align-items: center;
padding: 0 32rpx;
height: 88rpx;
font-size: 28rpx;
color: #333;
cursor: pointer;
transition: background 0.2s;
}
.drawer-item:active {
background: #f0faff;
color: #007aff;
}
.icon {
width: 40rpx;
height: 40rpx;
margin-right: 18rpx;
}
.drawer-footer {
padding: 24rpx 32rpx 32rpx 32rpx;
border-top: 1rpx solid #f0f0f0;
font-size: 24rpx;
color: #aaa;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
</style>
三、父页面集成与使用示例
<template>
<button @click="showDrawer = true">打开菜单</button>
<sidebar-drawer
:show.sync="showDrawer"
:menu="menuList"
side="left"
width="70vw"
@select="onMenuSelect"
>
<template #header>个人中心</template>
<template #footer>版本号 1.0.0</template>
</sidebar-drawer>
</template>
<script>
import SidebarDrawer from '@/components/SidebarDrawer.vue';
export default {
components: { SidebarDrawer },
data() {
return {
showDrawer: false,
menuList: [
{ key: 'home', label: '首页', icon: '/static/home.png' },
{ key: 'profile', label: '个人资料', icon: '/static/user.png' },
{ key: 'settings', label: '设置', icon: '/static/settings.png' },
],
};
},
methods: {
onMenuSelect(item) {
uni.showToast({ title: `点击了${item.label}`, icon: 'none' });
// 可根据 item.key 跳转页面
},
},
};
</script>
四、鸿蒙平台适配与优化建议
- 分辨率适配:全程使用
rpx
单位,保证鸿蒙不同设备下的显示一致。 - 手势优化:鸿蒙设备对滑动手势支持良好,建议侧滑关闭菜单时增加滑动距离判断。
- 动画与交互:鸿蒙设备对交互反馈要求高,建议菜单弹出/关闭使用 CSS3 动画。
- 安全区域适配:底部使用
env(safe-area-inset-bottom)
,兼容鸿蒙全面屏和异形屏。 - 无障碍适配:为菜单项添加 aria-label,提升鸿蒙无障碍体验。
五、实际应用案例
- 内容社区App:侧边栏集成个人中心、消息、设置等入口。
- 电商App:侧边栏快速切换分类、订单、客服等功能。
- 工具类App:侧边栏管理多账号、主题切换等。
六、总结与展望
自定义侧边栏菜单组件是提升移动端导航体验的重要工具。通过 UniApp 的组件化和跨平台特性,我们可以高效实现兼容鸿蒙的高性能侧边栏。未来还可结合动态菜单、权限控制、主题切换等进一步丰富场景。希望本文的讲解和代码示例能为你的项目带来启发,欢迎留言交流更多鸿蒙适配经验!