Vue组件 — 下拉菜单

97 阅读1分钟

组件介绍

版本: Vue: ^2.6.10

业务开发时,是面向iphone6/7/8 Plus

主要是面向移动端的组件, 采用vw布局

样式和布局(px或者vw),可根据代码自由改动

使用展示

image.png

image.png

代码

<template>
  <div>
    <div class="list-down">
      <button @click="onSelectTeam">
        <div class="select_team_container">
          <div class="select_team_left_part">
            <img :src="reportSelectClan.flag_url" alt="" srcset="" />
            <span class="select_team_name">{{
              reportSelectClan.short_name
            }}</span>
          </div>
          <div class="select_team_right_picture">
            <img
              v-show="teamSelectRightArrowIcon == 'up'"
              src="https://tva1.sinaimg.cn/large/e6c9d24egy1h633d6v26mj200f0090at.jpg"
              alt=""
              srcset=""
            />
            <img
              v-show="teamSelectRightArrowIcon == 'down'"
              src="https://tva1.sinaimg.cn/large/e6c9d24egy1h633d4q20hj200f0090an.jpg"
              alt=""
              srcset=""
            />
          </div>
        </div>
      </button>
      <ul
        id="list-chooses"
        :style="{ display: listChoosesBox, height: listChooseHeight + 'vw' }"
      >
        <li
          v-for="(item, index) in reportClanList"
          :key="index"
          @click="onChooseReportClan(item)"
        >
          <div class="select_team_item_container">
            <img
              :src="item.flag_url"
              class="select_team_item_picture"
              alt=""
              srcset=""
            />
            <div class="select_team_item_name">
              {{ item.short_name }}
            </div>
          </div>
        </li>
      </ul>
    </div>
  </div>
</template>

<script>
export default {
  name: "DropDownMenu",
  components: {},
  props: {
    // 选择元素
    reportSelectClanProp: {
      type: Object,
      default: () => {
        return {
          flag_url:
            "https://ts2.cn.mm.bing.net/th?id=OIP-C.ckYu63OifAf-IHXuxhDDkgHaHI&w=254&h=245&c=8&rs=1&qlt=90&o=6&dpr=1.1&pid=3.1&rm=2",
          short_name: "元素1",
        };
      },
    },
    // 列表集合
    reportClanListProp: {
      type: Array,
      default: () => [
        {
          flag_url:
            "https://ts2.cn.mm.bing.net/th?id=OIP-C.ckYu63OifAf-IHXuxhDDkgHaHI&w=254&h=245&c=8&rs=1&qlt=90&o=6&dpr=1.1&pid=3.1&rm=2",
          short_name: "元素1",
        },
        {
          flag_url:
            "https://ts2.cn.mm.bing.net/th?id=OIP-C.ckYu63OifAf-IHXuxhDDkgHaHI&w=254&h=245&c=8&rs=1&qlt=90&o=6&dpr=1.1&pid=3.1&rm=2",
          short_name: "元素2",
        },
        {
          flag_url:
            "https://ts2.cn.mm.bing.net/th?id=OIP-C.ckYu63OifAf-IHXuxhDDkgHaHI&w=254&h=245&c=8&rs=1&qlt=90&o=6&dpr=1.1&pid=3.1&rm=2",
          short_name: "元素3",
        },
        {
          flag_url:
            "https://ts2.cn.mm.bing.net/th?id=OIP-C.ckYu63OifAf-IHXuxhDDkgHaHI&w=254&h=245&c=8&rs=1&qlt=90&o=6&dpr=1.1&pid=3.1&rm=2",
          short_name: "元素4",
        },
        {
          flag_url:
            "https://ts2.cn.mm.bing.net/th?id=OIP-C.ckYu63OifAf-IHXuxhDDkgHaHI&w=254&h=245&c=8&rs=1&qlt=90&o=6&dpr=1.1&pid=3.1&rm=2",
          short_name: "元素5",
        },
        {
          flag_url:
            "https://ts2.cn.mm.bing.net/th?id=OIP-C.ckYu63OifAf-IHXuxhDDkgHaHI&w=254&h=245&c=8&rs=1&qlt=90&o=6&dpr=1.1&pid=3.1&rm=2",
          short_name: "元素6",
        },
        {
          flag_url:
            "https://ts2.cn.mm.bing.net/th?id=OIP-C.ckYu63OifAf-IHXuxhDDkgHaHI&w=254&h=245&c=8&rs=1&qlt=90&o=6&dpr=1.1&pid=3.1&rm=2",
          short_name: "元素7",
        },
        {
          flag_url:
            "https://ts2.cn.mm.bing.net/th?id=OIP-C.ckYu63OifAf-IHXuxhDDkgHaHI&w=254&h=245&c=8&rs=1&qlt=90&o=6&dpr=1.1&pid=3.1&rm=2",
          short_name: "元素8",
        },
      ],
    },
  },
  data() {
    return {
      reportSelectClan: this.reportSelectClanProp,
      reportClanList: this.reportClanListProp,
      listChoosesBox: "none",
      teamSelectRightArrowIcon: "down",
      listChooseHeight: 14.94,
      singleLiHeight: 3,
    };
  },
  watch: {
    reportClanListProp: function (val) {
      this.reportClanList = val;
    },
    reportSelectClanProp: function (val) {
      this.reportSelectClan = val;
    },
  },
  mounted() {
    this.judgeHeight();
  },
  methods: {
    // vw布局: 根据列表元素变换展开列表的高度
    judgeHeight() {
      let liAllHeight = this.reportClanList.length * this.singleLiHeight;
      if (liAllHeight < 14.94) {
        this.listChooseHeight = liAllHeight;
      } else {
        this.listChooseHeight = 14.94;
      }
    },
    // 展开列表
    listDown() {
      let startHeight = 0;
      let stopHeight = this.singleLiHeight;
      let timeId = setInterval(() => {
        startHeight++;
        document.querySelectorAll("#list-chooses li").forEach((item) => {
          item.style.height = startHeight + "vw";
        });
        if (startHeight >= stopHeight) {
          clearInterval(timeId);
        }
      }, 5);
      this.listChoosesBox = "block";
    },
    // 收起列表
    listUp() {
      let startHeight = this.singleLiHeight;
      let stopHeight = 0;
      let timeId = setInterval(() => {
        startHeight--;
        document.querySelectorAll("#list-chooses li").forEach((item) => {
          item.style.height = startHeight + "vw";
        });
        if (startHeight <= stopHeight) {
          clearInterval(timeId);
        }
      }, 5);
      setTimeout(() => {
        this.listChoosesBox = "none";
      }, 30);
    },
    // 展开或收起下拉列表
    onSelectTeam() {
      if (this.listChoosesBox == "none") {
        this.listDown();
        this.teamSelectRightArrowIcon = "up";
      } else if (this.listChoosesBox == "block") {
        this.listUp();
        this.teamSelectRightArrowIcon = "down";
      }
    },
    // 选择下拉列表中元素
    onChooseReportClan(item) {
      this.listUp();
      this.reportSelectClan = item;
      this.teamSelectRightArrowIcon = "down";
      this.$emit("chooseReportClanEvent", item);
    },
  },
};
</script>

<style lang="less" scoped>
.list-down {
  width: 159px;
  height: 25px;
  font-weight: 700;
  font-size: 12px;
  line-height: 20px;
  border: 1px solid #555;
  border-radius: 2px;
  position: relative;

  button {
    width: 159px;
    height: 25px;
    cursor: pointer;
    background: rgba(31, 34, 40, 0.95);
    border: none;
    color: #fff;
    text-align: left;

    .select_team_container {
      display: flex;
      justify-content: space-between;

      .select_team_left_part {
        display: flex;
        align-items: center;

        img {
          height: 15px;
          margin-right: 3px;
        }
      }

      .select_team_right_picture {
        width: 15px;
        height: 9px;

        .img {
          width: 100%;
          height: 100%;
        }
      }
    }
  }

  #list-chooses {
    list-style: none;
    padding: 0;
    margin: 0;
    position: absolute;
    top: 25px;
    left: 0;
    z-index: 999;
    overflow: scroll;

    li {
      width: 159px;
      height: 0;
      background: rgba(31, 34, 40, 0.95);
      color: #fff;
      line-height: 20px;
      font-weight: 700;
      font-size: 12px;
      border-bottom: 0.5px solid #555;

      .select_team_item_container {
        display: flex;
        align-items: center;
        padding-left: 6px;

        .select_team_item_picture {
          height: 15px;
          margin-right: 3px;
        }
      }
    }
  }
}
</style>