广告
返回顶部
首页 > 资讯 > 前端开发 > JavaScript >小程序原生实现左滑抽屉菜单
  • 443
分享到

小程序原生实现左滑抽屉菜单

2024-04-02 19:04:59 443人浏览 薄情痞子
摘要

目录WXS 响应事件方案A页面结构和样式WXS 事件回调函数WXS 脚本遮罩层方案B为什么要使用 WXS结语 & 参考资料参考资料:在移动端,侧滑菜单是一个很常用的组件(通常

在移动端,侧滑菜单是一个很常用的组件(通常称作 Drawer,抽屉)。因为现在手机屏幕太大,点击角落的菜单按钮明显不如在屏幕中间滑动方便。

相比其他平台,小程序的组件库支持明显还不够完善,各个框架也还不太成熟。由于之前使用框架的过程中被各种神秘bug搞的头秃,还是用回了原生环境。

最近研究了一下如何在原生框架中实现滑动抽屉菜单效果,本来以为很麻烦,结果发现其实只需要几十行代码,而且可以类比实现很多灵活的效果。感觉现在网上相关资料较少,因此在此分享一下。除了文中贴出的代码块,也可以点击链接在小程序开发工具中预览效果、查看代码片段。这里实现了三种常见效果,先看一下动图,下面将一一讲解代码实现。

A 菜单在上层 

A2 菜单在上层,下层遮罩 

B 菜单在下层

WXS 响应事件

手势控制菜单的原理很简单:小程序提供了一系列触摸手势触发的事件,包括触摸开始、移动、结束(touchstart, touchmove, touchend)等等。在这些事件上绑定自定义的事件响应函数,即可实现根据手势打开关闭菜单的操作。

出于性能考虑,事件处理函数最好放在 WXS、而不是 js 文件中。具体原理与小程序的运行环境有关,感兴趣的话可以去文末查看。WXS 是小程序的专用脚本语言(WXS 与 JS 的关系相当于 WXSS 与 CSS 的关系),语法和 JS 类似,有部分区别,比如:

  • 与 JS 隔离,不能调用其他 javascript 文件中定义的函数,也不能调用小程序提供的api
  • 只能响应小程序内置组件的事件,不支持自定义组件的事件回调
  • 变量与函数默认为模块私有,通过 module.exports 对外暴露
  • 使用标签在 WXML 中引入使用(必须使用相对路径)

wxs 文件和 wxml 文件中的基本写法如下:


// index.wxs

function touchStart(e, ins) {}
function touchMove(e, ins) {}
function touchEnd(e, ins) {}

module.exports = {
  touchstart: touchStart,
  touchmove: touchMove,
  touchend: touchEnd
}
<wxs module="drawer" src="./index.wxs"></wxs>

<view bindtouchstart="{{drawer.touchstart}}"
      bindtouchmove="{{drawer.touchmove}}" 
      bindtouchend="{{drawer.touchend}}">
</view>

方案A

页面结构和样式

这是最常见的抽屉菜单样式之一,滑动主体内容不动,菜单在上层显示。首先写出基本的 html 结构和 CSS 样式(省略了一些美观方面的样式表):


<wxs module="drawer" src="./index.wxs"></wxs>

<view>
  <view class="main" bindtouchstart="{{drawer.touchstart}}"
    bindtouchmove="{{drawer.touchmove}}" bindtouchend="{{drawer.touchend}}">
    <view>
      右滑显示侧边菜单 方案A
    </view>
  </view>

  <view class="drawer" data-drawerwidth="150">
    <view class="drawer-item">drawerA</view>
    <view wx:for="{{[1, 2, 3]}}" class="drawer-item">
      <text>menu item {{item}}</text>
    </view>
  </view>
</view>

WXML 中的几个重点:

  • 正确引入 wxs 模块(必须用相对路径)
  • 进行滑动手势时菜单是隐藏的,所以实际上是在主界面上进行滑动,所以三个滑动事件回调需要绑定在主体内容的 view 上面
  • 进行移动的是 .drawer 元素,需要设置好 class 属性方便获取
  • 抽屉元素的 data-drawerwidth 属性通过 dataset 传值给 wxs 脚本,规定了菜单的宽度,需要和样式保持一致

WXSS 没啥好说的,写在注释里了:


.main {
  height: 100vh;
  width: 100%;
  position: absolute;
}

.drawer {
  height: 100vh;
  width: 150px;
  position: absolute;
  transition: transfORM 0.4s ease; 
  left: -150px;  
}

WXS 事件回调函数

wxs 函数有两个入参

  • event 是小程序事件对象,并在此基础上多了触发事件的组件的实例 event.instance
  • ownerInstance 是触发事件的组件的父组件(页面)的实例

wxs 中组件实例是封装好的 ComponentDescriptor 对象,能够操作组件的 dataset、设置 style、class 等,对于交互动画基本够用了。更多用法可参考文档。


var wxsFunction = function(event, ownerInstance) {
    var instance = ownerInstance.selectComponent('.classSelector') // 返回组件的实例
    instance.setStyle({
        "font-size": "14px" // 支持rpx
    })
    instance.getDataset()
    instance.setClass(className)

    return false // 不往上冒泡,相当于调用了同时调用了stopPropagation和preventDefault
}

WXS 脚本

条件判断为主,逻辑没啥特别的,结合情景不难理解

  • 不要用 let, const 声明变量,会报错
  • 把设置 transform 属性 X 位移的代码简单封装一下,看起来更美观
  • judge point 类似于吸附效果,就是菜单划出来超过某一位置就自动把剩余部分打开

var startmark = 0;
var status = 0;  // 菜单开闭状态
var JUDGEPOINT = 0.7;

function touchStart(e, ins) {
  var pageX = (e.touches[0] || e.changedTouches[0]).pageX;
  startmark = pageX;
}

function touchMove(e, ins) {
  var pageX = (e.touches[0] || e.changedTouches[0]).pageX;
  var offset = pageX - startmark;
  var drawerComp = ins.selectComponent('.drawer');
  var drawerWidth = drawerComp.getDataset().drawerwidth;

  if (offset > 0 && status == 0) {
    setCompTransX(drawerComp, Math.min(drawerWidth, offset))
  } else if (offset < 0 && status == 1) {
    setCompTransX(drawerComp, Math.max(0, offset))
  }
}

function touchEnd(e, ins) {
  var pageX = (e.touches[0] || e.changedTouches[0]).pageX;
  var offset = pageX - startmark;
  var drawerComp = ins.selectComponent('.drawer');
  var drawerWidth = drawerComp.getDataset().drawerwidth;

  if (offset > 0 && status == 0) {
    if (offset < drawerWidth * JUDGEPOINT) {
      setCompTransX(drawerComp, 0);
    } else {
      setCompTransX(drawerComp, drawerWidth);
      status = 1;
    }
  } else if (offset < 0) {
    setCompTransX(drawerComp, 0);
    status = 0;
  }
}

function setCompTransX(comp, x) {
  comp.setStyle({
    transform: 'translateX(' + x + 'px)',
  })
}

module.exports = {
  touchstart: touchStart,
  touchmove: touchMove,
  touchend: touchEnd
}

遮罩层

点击文首或文末链接在小程序开发工具中查看完整代码。

遮罩层只需要在菜单和主容器之间增加一个 view 即可:


<view class="main"></view>
<view class="mask" data-maxopacity="0.6"></view>
<view class="drawer" data-drawerwidth="150"></view>

样式中很重要的是这个 pointer-events 属性,设置为 none 之后点击动作会穿透这个 view 达到下层。因为遮罩层不像抽屉是处在画面以外的,它虽然透明度为0,但实际上一直覆盖在 .main 上方,如果不加这个属性,所有对 .main 的点击操作都会点到 .mask 上面,那不管是滑动还是其他按钮都无效了。


.mask {
  height: 100vh;
  width: 100%;
  position: fixed;
  transition: opacity 0.4s ease;
  opacity: 0;
  pointer-events: none;
  background-color: #548CA8;
}

wxs 脚本也基本完全一致,只需要以相似的方法获取到 .mask 的实例以及 dataset 中的透明度参数,并在设置位移属性的同时设置遮罩层的透明度属性即可。


function setDrawer(x) {
  setCompTransX(drawerComp, x);
  maskComp.setStyle({
    opacity: x / drawerWidth * maskOpacity,
  })
}

方案B

点击文首或文末链接在小程序开发工具中查看完整代码。

方案B 与方案A 的区别主要在于滑动时是主界面向右移动露出下层的菜单,其余各部分实现并无不同。这里只贴出主要差异的部分。

因为移动的是 .main 元素,因此把宽度配置数据放到了该元素的标签中,这样可以少获取一个组件实例。


<view class="drawer"></view>

<view class="main" 
      data-drawerwidth="150" 
      bindtouchstart="{{drawer.touchstart}}"
      bindtouchmove="{{drawer.touchmove}}" 
      bindtouchend="{{drawer.touchend}}">
</view>

transition 动画属性也放在 .main 中,.drawer 的偏移不需要了。


.main {
  height: 100vh;
  width: 100%;
  position: absolute;
  transition: transform 0.4s ease;
}

.drawer {
  height: 100vh;
  width: 150px;
  position: absolute;
}

wxs 脚本中除了获取的组件不同外,连设置位移都不需要改。


function touchMove(e, ins) {
  var pageX = (e.touches[0] || e.changedTouches[0]).pageX;
  var offset = pageX - startmark;
  var mainComp = ins.selectComponent('.main');
  var drawerWidth = mainComp.getDataset().drawerwidth;

  if (offset > 0 && status == 0) {
    setCompTransX(mainComp, Math.min(drawerWidth, offset))
  } else if (offset < 0 && status == 1) {
    setCompTransX(mainComp, Math.max(0, offset))
  }
}

为什么要使用 WXS

小程序在很多地方与 WEB 开发很像,但底层存在一些区别。网页中,渲染和脚本执行在同一个线程中执行(因此执行脚本可能会导致页面整个卡死);小程序在不同的线程中分别运行逻辑层(JS脚本)和渲染层(WXML和WXSS),线程间经由客户端(Native)进行通信。

因此,如果使用 JS 脚本响应事件,每次触发 touchmove 都会产生两次进程间通信(下图左所示),通信开销较大;同时“setData 渲染也会阻塞其它脚本执行”(文档这么说的,我也不知道为什么)。由于一次手势会触发巨量的 touchmove 事件,上述原因会造成动画的卡顿。

而 WXS 函数运行在视图层,不存在上述问题(下图右所示)。

结语 & 参考资料

以上就是原生小程序的几种抽屉菜单实现方法,希望对你有所帮助;对于文中存在的疏漏欢迎讨论指正。

点击链接可以在小程序开发工具中查看完整代码(使用小程序开发工具的代码片段分享,对开发工具版本有一定要求)。他这个分享代码片段有点玄学,如果直接打开失败,可以在登录后尝试在“项目-导入代码片段”中直接输入链接或链接最后一段ID。

参考资料:

小程序框架/视图层/事件系统/WXS 响应事件

官方 demo

小程序宿主环境

到此这篇关于小程序原生实现左滑抽屉菜单的文章就介绍到这了,更多相关小程序 左滑抽屉菜单内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: 小程序原生实现左滑抽屉菜单

本文链接: https://www.lsjlt.com/news/131496.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 小程序原生实现左滑抽屉菜单
    目录WXS 响应事件方案A页面结构和样式WXS 事件回调函数WXS 脚本遮罩层方案B为什么要使用 WXS结语 & 参考资料参考资料:在移动端,侧滑菜单是一个很常用的组件(通常...
    99+
    2022-11-12
  • 小程序如何实现左滑抽屉菜单
    这篇文章将为大家详细讲解有关小程序如何实现左滑抽屉菜单,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。在移动端,侧滑菜单是一个很常用的组件(通常称作 Drawer,抽屉)。因为现在手机屏幕太大,点击角落的菜...
    99+
    2023-06-20
  • Android怎么实现侧滑抽屉菜单
    这篇文章将为大家详细讲解有关Android怎么实现侧滑抽屉菜单,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。侧滑抽屉菜单 前言正文一、创建项目二、添加滑动菜单三、UI美化四、添加导航视图五、菜单分类六、动...
    99+
    2023-06-14
  • Android 侧滑抽屉菜单的实现代码
    目录前言正文一、创建项目二、添加滑动菜单三、UI美化四、添加导航视图五、菜单分类六、动态菜单七、源码运行效果图: 前言   滑动菜单相信都不会陌生,你可能见...
    99+
    2022-11-11
  • Android开源AndroidSideMenu实现抽屉和侧滑菜单
    AndroidSideMenu能够让你轻而易举地创建侧滑菜单。需要注意的是,该项目自身并不提供任何创建菜单的工具,因此,开发者可以自由创建内部菜单。 核心类如下: p...
    99+
    2022-06-06
    菜单 抽屉 Android
  • 微信小程序实现点餐小程序左侧滑动菜单
    目录前言一、初识scroll-view二、左侧导航三、右侧滑动前言 最近在帮亲戚做一款微信的点餐小程序,以前从没有接触过小程序的我只能现做现卖。一边看文档一边实践尝试,在进行到点菜模...
    99+
    2022-11-13
  • Android实现自定义滑动式抽屉效果菜单
    在Andoird使用Android自带的那些组件,像SlidingDrawer和DrawerLayout都是抽屉效果的菜单,但是在项目很多要实现的功能都收到Android这些自...
    99+
    2022-06-06
    自定义 菜单 抽屉 Android
  • 微信小程序如何实现点餐小程序左侧滑动菜单
    这篇文章主要讲解了“微信小程序如何实现点餐小程序左侧滑动菜单”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“微信小程序如何实现点餐小程序左侧滑动菜单”吧!效果图:一、初识scroll-view...
    99+
    2023-07-02
  • 微信小程序实现菜单左右联动效果
    本文实例为大家分享了微信小程序实现菜单左右联动效果的具体代码,供大家参考,具体内容如下 原理 首先是获取数据,并且获取数据的长度(需要根据长度来计算元素的高度),通过遍历数据的内容通...
    99+
    2022-11-13
  • Android实现原生侧滑菜单的超简单方式
    先来看看效果图 当你点击菜单可以更改图标,例如点击happy,首页就会变一个笑脸,这个实现的过程超级简单 你需要使用ToolBar与DrawableLayout两个比较新的控...
    99+
    2022-06-06
    菜单 Android
  • 使用微信小程序实现滑动菜单效果
    使用微信小程序实现滑动菜单效果微信小程序作为一种快速开发并具有广泛应用的工具,为我们提供了多种实现滑动菜单效果的方法。本文将向您展示一种简单而实用的实现方式,帮助您在开发中轻松添加滑动菜单效果。准备工作在开始编码之前,我们需要先创建一个基本...
    99+
    2023-11-21
    微信小程序 实现 滑动菜单
  • uni-app制作小程序实现左右菜单联动效果
    目录前言一、示意图二、实现步骤与思路讲解1.静态页面的布局2.模拟数据格式3.左侧菜单的点击效果4.右侧菜单的联动效果三、具体实现代码1.页面结构2.相关样式3.业务逻辑部分前言 今...
    99+
    2022-11-16
    uni-app左右菜单联动 uni-app菜单联动 uni-app左右联动 uniapp 小程序菜单
  • 微信小程序如何实现左右滑动
    这篇文章将为大家详细讲解有关微信小程序如何实现左右滑动,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。项目整体效果项目部分功能点解析主页图片左滑右滑对应按钮变化首先我们来聊...
    99+
    2022-10-19
  • 微信小程序左侧栏滑动怎么实现
    微信小程序左侧栏滑动的方法:1.创建微信小程序项目;2.在index.wxml文件中添加页面设计代码;3.在index.wxss文件中添加样式代码;4.在index.js文件中添加实现文件滑动效果的代码;5.保存编辑的代码并进行调试即可。具...
    99+
    2022-10-04
  • 怎么用uni-app制作小程序实现左右菜单联动效果
    这篇文章主要介绍“怎么用uni-app制作小程序实现左右菜单联动效果”,在日常操作中,相信很多人在怎么用uni-app制作小程序实现左右菜单联动效果问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么用uni-...
    99+
    2023-07-04
  • 微信小程序中如何实现左滑删除效果
    小编给大家分享一下微信小程序中如何实现左滑删除效果,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!先看效果要实现的效果:1,当向左...
    99+
    2022-10-19
  • 微信小程序实现列表项左滑删除效果
    本文实例为大家分享了微信小程序实现列表项左滑删除效果的具体代码,供大家参考,具体内容如下 效果 图片 WXML <view class="container">...
    99+
    2022-11-12
  • 微信小程序实现联动菜单
    最近为了实现课程设计,也做了一些前端的东西,今天想要做一个联动菜单来实现一些功能。实现了,也来做做笔记。 第1步:了解一下 左右侧菜单其实简单来讲就是把一个区域分成左右两个部分。关于...
    99+
    2022-11-12
  • 微信小程序如何实现向左滑动删除功能
    这篇文章将为大家详细讲解有关微信小程序如何实现向左滑动删除功能,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。微信小程序 向左滑动删除功能的实现实现效果图:实现代码:1、w...
    99+
    2022-10-19
  • 微信小程序实现收缩式菜单
    本文实例为大家分享了微信小程序实现收缩式菜单的具体代码,供大家参考,具体内容如下 wxml文件 <view class="page"> <!--分类 -->...
    99+
    2022-11-13
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作