H5仿淘宝下拉多选框

这篇博客介绍了如何使用Vue.js结合Vant UI库实现下拉框的动画效果和多选功能。文章详细解析了导航栏的隐藏与显示动画,以及下拉框的内容展示和省份选择的逻辑。内容包括点击事件处理、数据绑定和DOM操作,同时展示了遮罩层的使用和下拉框的样式设计。通过实例代码,展示了如何处理省份列表的获取和多选状态的切换。
摘要由CSDN通过智能技术生成

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

本案例结合vant多选框 实现

这里只具体分析一下下拉框动画 内容多选效果 遮罩层

下拉框的实现

1、 通过对导航栏 position: fixed; top: 0px;transform: translate(-100%); 使他向上移动他自身高度的位置这样子就实现了刚开始的导航栏隐藏
2、通过点击使导航栏移动到固定的位置

<template>
  <div class="box">
    <!-- 顶部 -->
    <div class="top">
      <div class="top-item">
        <div>省份</div>
        <div class="top-item">
          <van-icon name="arrow-down" @click="control" />
        </div>
      </div>
      <div class="top-item">
        <div>级别</div>
        <div class="top-item">
          <van-icon name="arrow-down" />
        </div>
      </div>
    </div>
    <!-- 省份下拉展示框 -->
    <div class="downBox" :class="[downflag?'downward':'',upflag?'upward':'']" ref="downBox">
      <!-- 省份 -->
      <div class="overSCroll">
        <div
          class="downBox-item"
          v-for="(item,index) in provenceArr"
          :key="index"
          :id="index"
          :style="{'color':(item.flag?'rgba(253, 16, 16, 100)':'')}"
          @click="btnSelect(item,index)"
        >{{item.provinceName}}{{`(${item.total})`}}</div>
      </div>

      <div class="downBox-bottom">
        <div class="downBox-btn">重置</div>
        <div class="downBox-btn btn-red" @click="control">确定</div>
      </div>
    </div>

    <!-- 盒子撑起高度 -->
    <div style="width: 100vw;height: 42px;"></div>
    <!-- 内容 -->
    <div class="content">
      <!-- 遮罩层 -->
      <div class="overCurtain" :style="{'display':(downflag?'block':'none')}"></div>

      <div class="content-item">
        <van-checkbox-group v-model="result">
          <van-checkbox name="a">
            <div class="radio-item">
              <img
                src="https://img2.baidu.com/it/u=2102736929,2417598652&fm=26&fmt=auto&gp=0.jpg"
                alt
                style="height:75px;width:100px;border-radius: 4px;"
              />
              <div class="item-right">
                <div class="name">南湖梦幻岛</div>
                <div class="right-center">
                  <span style="font-size: 12px;"></span>
                  <span>39.9</span>
                </div>
                <div class="right-bottom">门票:98</div>
              </div>
            </div>
          </van-checkbox>
        </van-checkbox-group>
      </div>
    </div>
    <!-- 底部 -->
    <div class="bottom">
      <div class="bottom-left">
        <div class="bottom-left-top">基础费用:¥39.90</div>
        <div class="bottom-left-bottom">门票价值:¥98.00</div>
      </div>
      <button class="bottom-right">系统报价</button>
    </div>
  </div>
</template>

<script>
import travelApi from "@/travel";
import { formatProvince } from "@/utils";
export default {
  data() {
    return {
      downBoxHeight: 0,
      result: [],
      downflag: false,
      upflag: false,
      listParams: {
        limit: 40,
        page: 0,
        managerId: 0
      },
      provenceArr: []
    };
  },
  computed: {},
  watch: {},
  mounted() {
    document.title = "定制景区";
    this.listParams.managerId = Number(this.$route.query.id);
    this.getProvenceList();
  },
  methods: {
    // 多选
    btnSelect(item, index) {
      // this.$set(this.selectArr, index, !this.selectArr[index]);
      this.$set(item, "flag", !item.flag);
    },
    // 获得省份列表
    getProvenceList() {
      travelApi
        .DZAreaList(this.listParams)
        .then(res => {
          if (res.status == 200) {
            res.data.map(item => {
              let obj = {};
              obj.provinceId = item[0];
              obj.provinceName = formatProvince(item[0]);
              obj.total = item[1];
              obj.flag = false;
              this.provenceArr.push(obj);
            });

            this.selectArr = new Array(this.provenceArr.length).fill(false);
            this.$nextTick(() => {
              this.downBoxHeight = this.$refs.downBox.clientHeight;
            });
          }
          console.log(this.provenceArr, "我来了");
          console.log(this.downBoxHeight, "高度");
          console.log(this.selectArr, "数据");
        })
        .catch(err => {
          console.log(err);
        });
    },
    // control控制是否展开
    control() {
      console.log("我点到了");
      this.downflag = !this.downflag;
      this.upflag = !this.downflag;
      console.log(this.provenceArr, "通过flag为true 选择想对象的数据");
    }
  }
};
</script>

<style lang='scss' scoped>
.box {
  background-color: rgba(246, 246, 246, 100);
  min-height: 100vh;
  width: 100vw;

  //   顶部
  .top {
    width: 100vw;
    height: 42px;
    display: flex;
    align-items: center;
    justify-content: space-around;
    background-color: rgba(248, 248, 248, 100);
    position: fixed;
    top: 0px;
    z-index: 102;
    .top-item {
      display: flex;
      align-items: flex-end;
    }
  }

  //   内容区
  .content-item {
    width: calc(100% - 17px);
    height: 100px;
    padding-left: 17px;
    border-radius: 6px;
    background-color: rgba(255, 255, 255, 100);
    margin-bottom: 8px;
    display: flex;
    align-items: center;
    .radio-item {
      display: flex;
      align-items: center;
      width: 100%;
      .item-right {
        margin-left: 10px;
        height: 75px;
        .name {
          color: rgba(0, 0, 0, 1);
          font-size: 14px;
          height: 33%;
          display: flex;
          align-items: flex-start;
        }
        .right-center {
          color: rgba(253, 16, 16, 100);
          font-size: 16px;
          height: 33%;
          display: flex;
          align-items: center;
        }
        .right-bottom {
          color: rgba(140, 140, 140, 100);
          font-size: 11px;
          height: 33%;
          display: flex;
          align-items: flex-end;
        }
      }
    }
  }

  // 底部
  .bottom {
    position: fixed;
    bottom: 0px;
    width: calc(100vw - 34px);
    height: 54px;
    padding: 0 17px;
    background: white;
    display: flex;
    align-items: center;
    justify-content: space-between;
    .bottom-left {
      .bottom-left-top {
        color: rgba(0, 0, 0, 1);
        font-size: 18px;
      }
      .bottom-left-bottom {
        color: rgba(117, 117, 117, 100);
        font-size: 10px;
      }
    }

    .bottom-right {
      border-radius: 6px;
      background-color: rgba(253, 16, 16, 100);
      width: 137px;
      height: 38px;
      border: none;
      outline: none;
      color: rgba(255, 255, 255, 100);
      font-size: 18px;

      display: flex;
      justify-content: center;
      align-items: center;
    }
  }
}
//  遮罩层
.overCurtain {
  border-top: 1px solid rgb(230, 245, 255);

  position: absolute;

  height: calc(100vh - 1px);

  width: 100%;

  left: 0px;

  top: 0px; /*从左上角开始,覆盖整个页面*/

  opacity: 0.7; /*透明度*/

  background-color: black;

  z-index: 100; /*层,重叠时大的优先显示,默认为0。登陆框可以设为101*/

  display: none; /*开始不显示*/
}

.overSCroll {
  max-height: 205px;
  overflow: scroll;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  justify-content: space-between;
}
// 下拉
.downBox {
  width: calc(100vw - 42px);
  border-radius: 0px 0px 8px 8px;
  background: white;
  position: fixed;
  top: 0px;
  transform: translate(-100%);
  padding: 20px 21px 30px 21px;
  z-index: 101;
}

// 下拉框内容
.downBox-item {
  width: 30%;
  height: 40px;
  line-height: 40px;
  text-align: center;
}

.downBox-bottom {
  margin-top: 15px;
  width: 100%;
  align-items: center;
  display: flex;
  justify-content: space-between;
}
.downBox-btn {
  border: 1px solid rgba(111, 111, 111, 100);
  border-radius: 57px;
  width: 174px;
  height: 38px;
  display: flex;
  justify-content: center;
  align-items: center;
  color: rgba(34, 34, 34, 100);
  font-size: 14px;
}
.btn-red {
  border-radius: 57px;
  background-color: rgba(250, 49, 28, 100);
  border: none;
  color: white;
}
.downward {
  animation: downAnimation 0.5s ease-in;
  animation-fill-mode: forwards;
}
@keyframes downAnimation {
  from {
    transform: translateY(-100%);
  }
  to {
    transform: translateY(calc(0% + 42px));
  }
}
.upward {
  animation: upAnimation 0.5s ease-in;
  animation-fill-mode: forwards;
}
@keyframes upAnimation {
  from {
    transform: translateY(calc(0% + 42px));
  }
  to {
    transform: translateY(-100%);
  }
}
</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值