小程序实例:小程序实现折叠菜单的效果「附代码」

1. 前言

随着智能手机和移动互联网的普及,小程序成为越来越受欢迎的开发方式,尤其在微信生态圈中,已经成为一个不可或缺的角色。在小程序开发中,实现复杂的交互效果是非常重要的,而折叠菜单是其中一个常见的组件,可以让用户方便地折叠或展开内容,从而提高用户体验。接下来,我们将介绍如何使用小程序实现折叠菜单的效果。

2. 实现思路

我们将使用微信官方提供的小程序开发工具,以及小程序的原生控件和API来实现折叠菜单的效果。具体来说,我们将使用scroll-view组件来实现菜单的滚动效果,使用wxml模板语言和wxss样式语言来布局和美化菜单,而JavaScript代码则用来实现交互和动画效果。

3. 实现步骤

3.1 设计菜单数据

首先,我们需要将菜单的数据进行设计,包括菜单的分组和每个分组里面的子菜单。下面是一个示例数据:

var menuData = [

{

title: '主菜单1',

items: [

{ name: '子菜单1', page: 'page1' },

{ name: '子菜单2', page: 'page2' },

{ name: '子菜单3', page: 'page3' }

]

},

{

title: '主菜单2',

items: [

{ name: '子菜单4', page: 'page4' },

{ name: '子菜单5', page: 'page5' },

{ name: '子菜单6', page: 'page6' }

]

}

];

其中,menuData是一个包含两个主菜单的数组,每个主菜单有一个标题和若干个子菜单,每个子菜单有一个名称和对应的页面路径。

3.2 渲染菜单模板

接下来,我们将使用wxml模板语言来渲染菜单模板。具体来说,我们将使用block控件实现循环渲染主菜单和子菜单,还将使用view控件实现主菜单和子菜单的样式。

<scroll-view class="menu-scroll-view" scroll-y="true">

<block wx:for="{{menuData}}" wx:key="{{index}}">

<view class="menu-group">

<view class="menu-group-title">{{item.title}}</view>

<block wx:for="{{item.items}}" wx:key="{{index}}">

<view class="menu-item">{{item.name}}</view>

</block>

</view>

</block>

</scroll-view>

其中,scroll-view控件用来实现菜单的滚动效果,menu-scroll-view是我们自定义的样式类名,用来设置scroll-view控件的样式。

3.3 布局和美化菜单

接下来,我们将使用wxss样式语言来布局和美化菜单。具体来说,我们将使用flex布局和各种CSS样式来实现菜单的样式和动画效果。

.menu-scroll-view {

height: 100%;

}

.menu-group {

margin-right: 15px;

}

.menu-group-title {

font-size: 28rpx;

font-weight: bold;

margin-bottom: 8rpx;

}

.menu-item {

height: 60rpx;

line-height: 60rpx;

padding-left: 36rpx;

background-color: #fff;

border-bottom: 1px solid #e5e5e5;

font-size: 28rpx;

color: #666;

position: relative;

overflow: hidden;

transition: height 0.3s ease-out;

-webkit-transition: height 0.3s ease-out;

}

.menu-item::before {

content: '';

position: absolute;

left: 16rpx;

top: 25rpx;

width: 10rpx;

height: 10rpx;

background-color: #999;

transform: translate(0, -50%) rotate(45deg);

-webkit-transform: translate(0, -50%) rotate(45deg);

transition: transform 0.3s ease-out;

-webkit-transition: -webkit-transform 0.3s ease-out;

}

.menu-item-active {

height: 80rpx;

}

.menu-item-active::before {

transform: translate(0, -50%) rotate(-135deg);

-webkit-transform: translate(0, -50%) rotate(-135deg);

}

其中,我们使用了flex布局来实现主菜单和子菜单的排列效果,还使用了各种CSS样式来设置菜单的字体、颜色、背景和边框样式等。特别要注意的是,我们使用了position:relative和overflow:hidden样式来实现子菜单的折叠效果,使用了height属性和transition动画来实现子菜单的展开和折叠。

3.4 实现菜单交互效果

最后,我们将使用JavaScript代码来实现菜单的交互和动画效果。具体来说,我们将使用小程序的事件机制和API来处理菜单的触摸、点击、滚动和动画效果。

Page({

data: {

menuData: menuData

},

menuTouchStart: function (event) {

var itemId = event.currentTarget.dataset.itemId;

this.setData({

'touchStartItemId': itemId,

'touchStartY': event.touches[0].clientY,

'touchStartTimestamp': event.timeStamp

});

},

menuTouchEnd: function (event) {

var itemId = event.currentTarget.dataset.itemId;

var menuHeight = event.currentTarget.clientHeight;

var touchEndY = event.changedTouches[0].clientY;

var touchEndTimestamp = event.timeStamp;

var touchStartItemId = this.data.touchStartItemId;

var touchStartY = this.data.touchStartY;

var touchStartTimestamp = this.data.touchStartTimestamp;

var swipeMinDistance = 30; //swipe最小滑动距离

var swipeMinVelocity = 0.3; //swipe最小滑动速度

var swipeMaxTime = 300; //swipe最大滑动时间

var swipeDistance = touchEndY - touchStartY;

var swipeTime = touchEndTimestamp - touchStartTimestamp;

var swipeVelocity = swipeDistance / swipeTime;

var touchDirection = swipeDistance > 0 ? 'down' : 'up';

//判断是否滑动足够远、足够快且时间不超过300ms

if (Math.abs(swipeDistance) > swipeMinDistance && Math.abs(swipeVelocity) > swipeMinVelocity && swipeTime < swipeMaxTime) {

if (touchDirection === 'down') {

this.menuItemCollapse(touchStartItemId);

} else if (touchDirection === 'up') {

this.menuItemExpand(touchStartItemId);

}

} else { //如果不是swipe操作,则判断为click操作

var item = this.getMenuItemById(itemId);

if (item) {

wx.navigateTo({

url: '/' + item.page //跳转到对应的页面

});

}

}

},

menuScroll: function (event) {

var scrollTop = event.detail.scrollTop;

var menuItems = this.getMenuItems();

for (var i = 0; i < menuItems.length; i++) {

var menuItem = menuItems[i];

var menuItemRect = menuItem.getBoundingClientRect();

if (menuItemRect.top < 100 && menuItemRect.bottom > 100) { //如果菜单项被滚动到了中间位置,则高亮显示

if (menuItem.dataset.itemId != this.data.activeItemId) {

this.setData({

'activeItemId': menuItem.dataset.itemId

});

}

break;

}

}

},

menuItemExpand: function (itemId) {

var menuItem = this.getMenuItemById(itemId);

if (menuItem) {

menuItem.classList.add('menu-item-active');

}

},

menuItemCollapse: function (itemId) {

var menuItem = this.getMenuItemById(itemId);

if (menuItem) {

menuItem.classList.remove('menu-item-active');

}

},

getMenuItems: function () {

var query = wx.createSelectorQuery();

query.selectAll('.menu-item').boundingClientRect();

return query.exec(function (res) {

return res[0];

}) || [];

},

getMenuItemById: function (itemId) {

var query = wx.createSelectorQuery();

query.select('#menu-item-' + itemId).boundingClientRect();

return query.exec(function (res) {

return res[0];

}) || null;

}

});

其中,我们使用了Page()函数来定义小程序页面,定义了页面的data属性和一些处理触摸、点击、滚动和动画效果的函数。具体来说,我们使用menuTouchStart()和menuTouchEnd()函数来处理菜单的触摸事件,使用menuScroll()函数来处理菜单的滚动事件,使用menuItemExpand()和menuItemCollapse()函数来实现子菜单的展开和折叠效果,使用getMenuItems()和getMenuItemById()函数来获取菜单项的相关信息。

4. 代码实现

以上就是本次小程序实例的全部内容,我们在下面附上完整的代码,供大家参考学习。

var menuData = [

{

title: '主菜单1',

items: [

{ name: '子菜单1', page: 'page1' },

{ name: '子菜单2', page: 'page2' },

{ name: '子菜单3', page: 'page3' }

]

},

{

title: '主菜单2',

items: [

{ name: '子菜单4', page: 'page4' },

{ name: '子菜单5', page: 'page5' },

{ name: '子菜单6', page: 'page6' }

]

}

];

Page({

data: {

menuData: menuData

},

menuTouchStart: function (event) {

var itemId = event.currentTarget.dataset.itemId;

this.setData({

'touchStartItemId': itemId,

'touchStartY': event.touches[0].clientY,

'touchStartTimestamp': event.timeStamp

});

},

menuTouchEnd: function (event) {

var itemId = event.currentTarget.dataset.itemId;

var menuHeight = event.currentTarget.clientHeight;

var touchEndY = event.changedTouches[0].clientY;

var touchEndTimestamp = event.timeStamp;

var touchStartItemId = this.data.touchStartItemId;

var touchStartY = this.data.touchStartY;

var touchStartTimestamp = this.data.touchStartTimestamp;

var swipeMinDistance = 30; //swipe最小滑动距离

var swipeMinVelocity = 0.3; //swipe最小滑动速度

var swipeMaxTime = 300; //swipe最大滑动时间

var swipeDistance = touchEndY - touchStartY;

var swipeTime = touchEndTimestamp - touchStartTimestamp;

var swipeVelocity = swipeDistance / swipeTime;

var touchDirection = swipeDistance > 0 ? 'down' : 'up';

//判断是否滑动足够远、足够快且时间不超过300ms

if (Math.abs(swipeDistance) > swipeMinDistance && Math.abs(swipeVelocity) > swipeMinVelocity && swipeTime < swipeMaxTime) {

if (touchDirection === 'down') {

this.menuItemCollapse(touchStartItemId);

} else if (touchDirection === 'up') {

this.menuItemExpand(touchStartItemId);

}

} else { //如果不是swipe操作,则判断为click操作

var item = this.getMenuItemById(itemId);

if (item) {

wx.navigateTo({

url: '/' + item.page //跳转到对应的页面

});

}

}

},

menuScroll: function (event) {

var scrollTop = event.detail.scrollTop;

var menuItems = this.getMenuItems();

for (var i = 0; i < menuItems.length; i++) {

var menuItem = menuItems[i];

var menuItemRect = menuItem.getBoundingClientRect();

if (menuItemRect.top < 100 && menuItemRect.bottom > 100) { //如果菜单项被滚动到了中间位置,则高亮显示

if (menuItem.dataset.itemId != this.data.activeItemId) {

this.setData({

'activeItemId': menuItem.dataset.itemId

});

}

break;

}

}

},

menuItemExpand: function (itemId) {

var menuItem = this.getMenuItemById(itemId);

if (menuItem) {

menuItem.classList.add('menu-item-active');

}

},

menuItemCollapse: function (itemId) {

var menuItem = this.getMenuItemById(itemId);

if (menuItem) {

menuItem.classList.remove('menu-item-active');

}

},

getMenuItems: function () {

var query = wx.createSelectorQuery();

query.selectAll('.menu-item').boundingClientRect();

return query.exec(function (res) {

return res[0];

}) || [];

},

getMenuItemById: function (itemId) {

var query = wx.createSelectorQuery();

query.select('#menu-item-' + itemId).boundingClientRect();

return query.exec(function (res) {

return res[0];

}) || null;

}

});

5. 总结

本文介绍了如何使用微信小程序实现折叠菜单的效果,涵盖了菜单数据设计、菜单模板渲染、菜单布局和美化、菜单交互和动画效果等方面的内容。通过本文的学习,相信大家可以掌握如何使用小程序来实现复杂的交互效果,也希望本文能够对大家的小程序开发之路有所帮助。