原生微信小程序,实现 下拉菜单 ,带遮罩层,出现隐藏动画(dropDownMenu思路总结)

原生微信小程序,实现 下拉菜单 ,带遮罩层,出现隐藏动画(dropDownMenu思路总结)

实现效果

在这里插入图片描述
先上代码,下面开始做总结
.wxml 代码

<!-- 导航栏循环 -->
<view class="wrap">
	<view
	 data-id="{{item.id}}"
	 bind:tap="handleClick"
	 wx:for="{{navItem}}"
	 class="item {{item.isActive?'active':''}}"
	>
		{{item.name}}
	</view>
</view>
<!-- 选项循环 -->
<view class="selectWrap {{showOrHide?'slidown':'slidup'}}">
	<!-- 每项 -->
	<view
	 class="selectItem {{item.itemIsActive?'active':''}}"
	 wx:for="{{selectedItem}}"
	 data-contant="{{item.name}}"
	 bind:tap="closeMask"
	>
		{{item.name}}
	</view>
</view>
<!-- 遮罩层 -->
<view class="{{showOrHide?'shadow':''}}" bind:tap="closeMask" />
<scroll-view class="numwrap" scroll-y="{{true}}">
	<view>1</view>
	<view>2</view>
	<view>3</view>
	<view>4</view>
	<view>5</view>
	<view>6</view>
	<view>7</view>
	<view>8</view>
	<view>9</view>
	<view>10</view>
	<view>11</view>
	<view>12</view>
	<view>13</view>
	<view>14</view>
	<view>15</view>
	<view>16</view>
	<view>17</view>
	<view>18</view>
	<view>19</view>
	<view>20</view>
	<view>21</view>
	<view>22</view>
	<view>23</view>
	<view>24</view>
	<view>25</view>
	<view>26</view>
	<view>27</view>
	<view>28</view>
	<view>29</view>
	<view>30</view>
	<view>31</view>
	<view>32</view>
	<view>33</view>
	<view>34</view>
	<view>35</view>
	<view>36</view>
	<view>37</view>
	<view>38</view>
	<view>39</view>
	<view>40</view>
	<view>41</view>
	<view>42</view>
	<view>43</view>
	<view>44</view>
	<view>45</view>
	<view>46</view>
	<view>47</view>
	<view>48</view>
	<view>49</view>
	<view>50</view>
</scroll-view>

.wxss代码(less 和 wxss 都发一下)
.wxss

/* pages/character/character.wxss */
page {
  position: relative;
}
.wrap {
  border-bottom: 1px solid #000;
  background-color: #fff;
  position: fixed;
  color: #777777;
  width: 100vw;
  display: flex;
  z-index: 100;
}
.wrap .item {
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 20rpx;
  flex: 1;
}
.wrap .active {
  color: #F75194;
}
.selectWrap {
  color: #777777;
  position: absolute;
  width: 100%;
  top: 82rpx;
  z-index: 90;
  background-color: #fff;
}
.selectWrap .selectItem {
  padding: 20rpx;
  border-bottom: 1px solid #dddddd;
}
.selectWrap .active {
  color: #F75194;
}
.shadow {
  position: absolute;
  top: 0;
  width: 100%;
  height: 100vh;
  z-index: 4;
  background-color: #4C4C4C;
  opacity: 0.6;
}
.numwrap {
  padding-top: 82rpx;
  height: calc(100vh - 82rpx);
}
@keyframes slidown {
  0% {
    transform: translateY(-100%);
  }
  100% {
    transform: translateY(0);
  }
}
.slidown {
  display: block;
  animation: slidown 0.1s ease-in both;
}
@keyframes slidup {
  from {
    transform: translateY(0);
  }
  to {
    transform: translateY(-100%);
  }
}
.slidup {
  display: block;
  animation: slidup 0.1s ease-in both;
}

记得在 app.wxss 中配置一下默认样式

view,
swiper,
swiper-item,
navigator {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
}

.less

/* pages/character/character.wxss */
page {
    position: relative;
}

.wrap {
    border-bottom: 1px solid #000;
    background-color: #fff;
    position: fixed;
    color: #777777;
    width: 100vw;
    display: flex;
    z-index: 100;

    .item {
        display: flex;
        justify-content: center;
        align-items: center;
        padding: 20rpx;
        flex: 1;
    }

    .active {
        color: #F75194;
    }
}



.selectWrap {
    color: #777777;
    position: absolute;
    width: 100%;
    top: 82rpx;
    z-index: 90;
    background-color: #fff;

    .selectItem {
        padding: 20rpx;
        border-bottom: 1px solid #dddddd;
    }

    .active {
        color: #F75194;
    }
}

.shadow {
    position: absolute;
    top: 0;
    width: 100%;
    height: 100vh;
    z-index: 4;
    background-color: #4C4C4C;
    opacity: 0.6;
}

.numwrap {
    padding-top: 82rpx;
    height: calc(100vh - 82rpx);
}

@keyframes slidown {
    0% {
        transform: translateY(-100%);
    }

    100% {
        transform: translateY(0);
    }
}

.slidown {
    display: block;
    animation: slidown 0.1s ease-in both;
}

@keyframes slidup {
    from {
        transform: translateY(0);
    }

    to {
        transform: translateY(-100%);
    }
}

.slidup {
    display: block;
    animation: slidup 0.1s ease-in both;
}

.js 文件

// pages/character/character.js
Page({
  data: {
    // 菜单栏原始数据
    navItem: [
      {
        id: 0,
        name: "初始星级",
        isActive: false
      },
      {
        id: 1,
        name: "输出占位",
        isActive: false
      },
      {
        id: 2,
        name: "攻击类型",
        isActive: false
      }
    ],
    // 下拉选项原始数据
    selectItem: [
      {
        id: 0,
        rank: [
          {
            name: "初始星级",
            itemIsActive: true
          },
          {
            name: "初始一星",
            itemIsActive: false
          },
          {
            name: "初始二星",
            itemIsActive: false
          },

          {
            name: "初始三星",
            itemIsActive: false
          },
        ],
      },
      {
        id: 1,
        rank: [
          // "输出占位", "前卫", "中卫", "后卫"
          {
            name: "输出占位",
            itemIsActive: true
          },
          {
            name: "前卫",
            itemIsActive: false
          },
          {
            name: "中卫",
            itemIsActive: false
          },
          {
            name: "后卫",
            itemIsActive: false
          }
        ],
      },
      {
        id: 2,
        rank: [
          // "攻击类型", "魔法攻击", "物理攻击"
          {
            name: "攻击类型",
            itemIsActive: true
          },
          {
            name: "魔法攻击",
            itemIsActive: false
          },
          {
            name: "物理攻击",
            itemIsActive: false
          },
        ]
      }
    ],
    // 下拉选项,被选中那组的数据,由下面的js控制赋值
    selectedItem: [],
    // 记录菜单栏第几项被点开,方便对样式的绑定
    listNum: -1,
    // 下拉选项的隐藏和显示,默认隐藏
    showOrHide: false
  },
  // 点击菜单栏触发的事件函数
  handleClick: function (e) {
    const index = e.currentTarget.dataset.id;
    const { selectItem, navItem } = this.data;
    // 点击事件,开始时一定会执行的,先令所有下拉选项先隐藏
    const promise = new Promise((res) => {
      this.setData({
        showOrHide: false
      })
      res()
    })
    promise.then(() => {
      // 定义一个延迟0.1秒的函数,和函数动画事件对上
      setTimeout(() => {
        // 当点击的是已经点开的菜单项,则隐藏
        if (this.data.listNum === index) {
          navItem[index].isActive = false
          // 重置所有样式
          this.setData({
            navItem,
            listNum: -1
          })
          return;
        } else {
          // 否则就令当前的index = listNum方便下一次判断
          this.setData({
            listNum: index
          })
        }
        // 令当前点击的菜单栏高亮
        navItem.forEach((v, i) => i === index ? v.isActive = true : v.isActive = false)
        this.setData({
          showOrHide: true,
          selectedItem: selectItem[index].rank,
          navItem
        })
      }, 100)
    })
  },
  // 关闭下拉选项的函数
  // 两种情况下会关闭下拉选项
  //  1. 选择下拉选项,选择后被选的下拉选项高亮,关闭下拉选项列表
  //  2. 点击遮罩层关闭 
  closeMask: function (e) {
    let { navItem, listNum, selectedItem } = this.data;
    // 获取点击的下拉选项内容
    const { contant } = e.currentTarget.dataset
    // 被点击的下拉选项高亮
    selectedItem.forEach((v) => v.name === contant ? v.itemIsActive = true : v.itemIsActive = false)
    // 判断点击的是遮罩层还是下拉选项,如果是下拉选项则把选择的内容赋值到导航栏上,并且把v.isActive = false,让菜单栏高亮消失
    // 如果不是,不用赋值,直接把v.isActive = false,让菜单栏高亮消失
    contant ? (navItem.forEach((v, i) => {
      (i === listNum ? (v.name = contant) : (v.name = v.name));
      v.isActive = false
    })) : (navItem.forEach((v) => v.isActive = false))
    this.setData({
      listNum: -1,
      showOrHide: false,
      navItem,
      selectedItem
    })
  }
})

下面开始 技术 和 思路 总结
( 1 ). wxml 部分基本上正常排版就行,后面通过 wxss 和 js都能实现功能,这部分比较灵活

( 2 ). wxss 部分需要注意的是

  • 1 . 在全局 app.wxss 设置初始化样式 p0+m0+bz
  • 2 . 设置菜单栏的position: fixed;固定定位display: flex;弹性盒子,菜单栏的每个子项设置
    display: flex; justify-content: center; align-items: center; padding: 20rpx; flex: 1;使每项水平垂直居中,并且每项分配的距离相等
  • 3 . 选择项的position: absolute;一定要设置为绝对定位,并设置背景颜色background-color: #fff;如果不设置背景颜色就会出现这种情况
    在这里插入图片描述
  • 4 . 遮罩层设置,这里一定要设置的是position: absolute;宽高width: 100%; height: 100vh;vh表示的是屏幕的视口高度(同理vw表示视口宽度),opacity: 0.6;不设置透明度会导致下面的内容看不到
  • 5 . 最重要的就是z-index:属性的设置,导航栏 > 选项栏 > 遮罩层,这三个地方都要设置z-index属性,且层级大小一定要注意

( 3 ). js 部分,每个人思路不一样,但基本上都八九不离十,这里大体说一下我自己的思路

  • 1 . 定义点击显示下拉选项函数
  • 2 . 定义点击关闭下拉选项函数
    ( 这部分可以看js代码的注释,写的很清楚了,主要大量运用了 forEach 遍历数据,并对数据进行修改,熟练使用 三元表达式 )

代码gitee地址:https://gitee.com/chenminghuisir/wechat-applet-component
代码保存在仓库,PrincessConnect文件里

猜你喜欢

转载自blog.csdn.net/qq_40893035/article/details/108463045