微信小程序实现下拉框菜单附带遮罩层背景

实现功能

实现了点击按钮可以展开下拉选项菜单栏,并提供相关参自定义对应属性。

  1. 点击按钮弹出下拉菜单
  2. 自定义更改菜单文字颜色大小
  3. 包含遮罩层背景
  4. 新增功能1:自定义整个组件的层级
  5. 新增功能2:是否启用遮罩层背景
  6. 新增功能3:是否需要菜单标题(不加就不启用),且设置只显示4个字防止溢出
  7. 新增功能4:提供展开菜单和关闭菜单事件
  8. 新增功能5:提供两种样式

相关参数

options

展示的菜单列表

itemIndex

指定第一次选择的子项目

preTitle

菜单前置文字(如果不传则只显示menuTitle)

menuTitle

菜单名称(不传则默认第一个值)

menuColor

菜单栏文字颜色

menuSize

菜单栏文字大小

activeColor

选中的文字颜色

itemSize

选择的文字大小

zIndex

组件的层级

相关事件

bind:openMenu

打开菜单栏事件

bind:closeMenu

关闭菜单栏事件

bind:choose

选择子菜单事件

组件代码

dropdownMenu.wxml

<!-- 
  @name:微信小程序下拉框菜单组件
  @author: 柳吟风
  @version: 1.0.0
 -->
<!-- 
  ################各变量解释:
  options: 展示的菜单列表
  itemIndex: 指定第一次选择的子项目
  preTitle: 菜单前置文字(如果不传则只显示menuTitle)
  menuTitle: 菜单名称(不传则默认第一个值)
  menuColor: 菜单栏文字颜色
  menuSize: 菜单栏文字大小
  activeColor: 选中的文字颜色
  itemSize: 选择的文字大小
  zIndex: 层级
  isMask: 是否需要遮罩层背景

  ###############事件解释
  bind:openMenu 打开菜单栏事件
  bind:closeMenu 关闭菜单栏事件
  bind:choose 选择子菜单事件
-->
<view class="container" style="z-index: {{zIndex}}">
  <view bindtap="{{isMenuOpen?'closeMenu':'openMenu'}}" class="dropdown-title" style="font-size: {{menuSize}}rpx">
    <view wx:if="{{preTitle}}" style="color: {{menuColor}}">{{preTitle}}:</view>
    <text class="endEllipsis" style="color: {{activeMenu?activeColor:'#111'}}">{{activeMenu?options[choosed].text:menuTitle}}</text>
    <text class="arrow {{isMenuOpen?'up': 'down'}}" />
  </view>
  <view class="dropdown-menu {{isMenuOpen ? 'open' : ''}}">
    <block wx:for="{{options}}" wx:key="index">
      <view class="menu-item" style="font-size:{{itemSize}}rpx;{{choosed==index? 'color: '+activeColor:''}}" bindtap="selectItem" data-item="{{item}}" data-index="{{index}}">
        <view class="item-both">
          <text>{{item.text}}</text>
          <text wx:if="{{choosed==index}}" class="checkmark" />
        </view>
      </view>
    </block>
  </view>
</view>
<view wx:if="{{showMaskLayer&&isMask}}" class="mask" style="z-index: {{zIndex-1}};" bind:tap="{{isMenuOpen?'closeMenu':'openMenu'}}" />

dropdownMenu.js

Component({
  /**
   * 组件的属性列表
   */
  properties: {
    options: {
      type: Array,
      value: null
    },
    itemIndex: {
      type: Number,
      value: -1
    },
    preTitle: {
      type: String,
      value: null
    },
    menuTitle: {
      type: String,
      value: null
    },
    menuColor: {
      type: String,
      value: '#111'
    },
    menuSize: {
      type: Number,
      value: 32
    },
    activeColor: {
      type: String,
      value: "rgb(255, 69, 0)"
    },
    itemSize: {
      type: Number,
      value: 28
    },
    zIndex: {
      type: Number,
      value: 2
    },
    isMask: {
      type: Boolean,
      value: true
    },
    shrink: {
      type: Boolean,
      value: false
    }
  },

  /**
   * 组件的初始数据
   */
  data: {
    isMenuOpen: false,
    choosed: -1,
    showMaskLayer: false,
    activeMenu: false
  },

  /**
   * 组件的方法列表
   */
  methods: {
    /* 重置组件 */
    resetMenu: function () {
      this.setData({
        choosed: -1,
        activeMenu: false
      })
    },
    /* 是否显示遮罩层阴影 */
    showMask() {
      this.setData({
        showMaskLayer: true
      });
    },
    /* 展开子菜单 */
    openMenu: function () {
      this.setData({
        showMaskLayer: true,
        isMenuOpen: true
      });
      // 给父组件传递事件
      this.triggerEvent('openMenu')
    },
    /* 关闭子菜单 */
    closeMenu: function () {
      this.setData({
        showMaskLayer: false,
        isMenuOpen: false
      });
      // 给父组件传递事件
      this.triggerEvent('closeMenu')
    },
    /* 选择子菜单内容 */
    selectItem: function (e) {
      let dataset = e.currentTarget.dataset
      this.setData({
        showMaskLayer: false,
        isMenuOpen: false,
        activeMenu: true,
        choosed: dataset.index
      })
      // 给父组件传递数据
      this.triggerEvent('choose', {
        'index': dataset.index,
        'item': dataset.item
      })
    }
  },
  lifetimes: {
    ready() {
      if (this.properties.menuTitle == null) {
        this.setData({
          choosed: 0,
          activeMenu: true
        })
      }
      let itemIndex = this.properties.itemIndex
      if (itemIndex >= 0) {
        this.setData({
          choosed: itemIndex,
          activeMenu: true
        })
      }
    }
  }
})

dropdownMenu.wxss

.container {
  position: relative
}

.item-both {
  display: flex;
  align-items: center;
  justify-content: space-between
}

.dropdown-title {
  align-items: center;
  display: flex;
  background-color: #fff;
  padding: 10rpx;
}

.endEllipsis {
  display: -webkit-box;
  word-break: break-all;
  text-overflow: ellipsis;
  /* 只显示4个字 */
  width: 4em;
  /* 溢出用省略号显示 */
  overflow: hidden;
  -webkit-line-clamp: 1;
  /*设置需要显示的行数*/
  -webkit-box-orient: vertical;
}

.dropdown-menu {
  position: fixed;
  top: auto;
  /* 根据你的按钮高度和间距调整 */
  left: 0;
  right: 0;
  /* 根据需要调整宽度 */
  background-color: #fff;
  /* 边框阴影 */
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
  overflow: hidden;
  /* 初始高度为0,用于隐藏菜单 */
  max-height: 0;
  overflow-y: auto;
  /* 允许内容溢出时滚动 */
  transition: max-height 0.3s ease-out, opacity 0.3s ease-out;
  /* 初始透明度为0 */
  opacity: 0;
}

.dropdown-menu.open {
  /* 根据你的菜单项数量和高度调整 */
  max-height: 260rpx;
  /* 将透明度改为1进行显示 */
  opacity: 1;
  width: 100%;
}

.menu-item {
  margin: 20rpx;
  padding-bottom: 20rpx;
  border-bottom: 1px solid #eee;
}

.menu-item:last-child {
  border-bottom: none;
  padding-bottom: 0;
}

/* 箭头 */
.arrow {
  /* 跟左边文字有点距离 */
  margin-left: 10rpx;
  width: 0;
  height: 0;
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
}

.arrow.up {
  /* 可根据需求调整颜色 */
  border-bottom: 10rpx solid rgb(187, 187, 187);
}

.arrow.down {
  /* 可根据需求调整颜色 */
  border-top: 10rpx solid rgb(187, 187, 187);
}

/* 勾的实现 */
.checkmark {
  width: 20rpx;
  height: 10rpx;
  /* 设置勾的颜色 */
  border-left: 4rpx solid rgb(255, 69, 0);
  border-bottom: 5rpx solid rgb(255, 69, 0);
  /* 旋转形成勾的形状 */
  transform: rotate(-50deg);
}

/* 遮罩层 */
.mask {
  position: fixed;
  top: auto;
  left: 0;
  width: 100%;
  height: 100%;
  /* 半透明黑色背景 */
  background-color: rgba(0, 0, 0, 0.5);
}

引用示例

index.wxml

<dropdownmenu options="{{options}}" pre-title="推荐" menu-title="热门目录" menu-size="28" item-size="28" bind:choose="chooseItem" bind:openMenu="closeOtherMenu" />
<dropdownmenu options="{{options}}" menu-title="热门目录" menu-size="28" item-size="28" bind:choose="chooseItem" bind:openMenu="closeOtherMenu" />
<dropdownmenu options="{{options}}" menu-size="28" item-size="28" bind:choose="chooseItem" bind:openMenu="closeOtherMenu" />

index.js

Page({
  data: {
    isMenuOpen: false,
    options: [{
        text: '新款手机',
        value: 0
      },
      {
        text: '旧款手机',
        value: 1
      },
      {
        text: '促销活动',
        value: 2
      },
      {
        text: '热卖商场',
        value: 3
      },
      {
        text: '低价专区',
        value: 4
      },
    ],
    choosed: 0
  },
  /* 下拉框选择的数据 */
  chooseItem(e) {
    console.log(e)
  }
});

index.json

{
  "usingComponents": {
    "dropdownmenu": "/components/dropdownMenu/dropdownMenu"
  }
}

案例效果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值