模拟vant indexBar实现城市列表

Posted ws-zhangbo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了模拟vant indexBar实现城市列表相关的知识,希望对你有一定的参考价值。

<template>
  <div class="selectCityMain" ref="DOM" id="pageId">
    <div ref="Box">
      <!-- <div v-if="letter.length > 0" class="now-sort">{{letter}}</div> -->
      <div :class="[‘now-letter‘, fadeFlag?‘fadeIn‘:‘‘]">{{ letter }}</div>
      <div class="letterBox">
        <p :class="idx === activtIndex ? ‘active‘:‘‘" v-for="(item, idx) in letterList" :key="idx" @click="scrollSelect(idx)">{{ item }}</p>
      </div>
      <div>
        <div class="hostCityBox">
          <div
            class="base-wrap"
            v-for="(item, index) in quickPanelData"
            :classesAttr="item"
            :key="index"
          >
            <div class="title">{{item.title}}</div>
            <div class="panel host" ref="host">
              <span
                class="item ellipsis"
                v-for="(cy,idx) in item.data"
                :key="idx"
                @click="selectCity(cy)"
              >{{cy}}</span>
            </div>
          </div>
        </div>
        <div class="cityListBox" ref="left">
          <div class="base-wrap" v-for="(tle,tleIdx) in listData" :key="tleIdx">
            <div class="title_bar">{{tle.initial}}</div>
            <div class="panel">
              <p
                class="cityName border_bottom"
                v-for="(city,idx1) in tle.list"
                :key="idx1"
                @click="selectCity(city.name)"
              >{{city.name}}</p>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
import request from @/utils/request

export default {
  data() {
    return {
      cityname: "",
      citycode: "",
      city: "",
      province: "",
      listData: [],
      letterList: [],
      letter: "",
      fadeFlag: false,
      scrolly: 0,
      activtIndex:0,
      quickPanelData: [
        {
          title: "当前城市",
          navName: "",
          data: [杭州市],
        },
        {
          title: "热门城市",
          navName: "",
          data: [
            "北京市"
          ],
        }
      ],
      listHeight: []
    };
  },
  watch:{
    listData() {
      this.$nextTick(() =>{
        this._getHeight()
        let page = document.getElementById(pageId);
        // 先给页面注册滚动事件
        page.addEventListener("scroll", this.handleScroll, true);
      })
    }
  },
  async created() {
    this.getCityList();
  },
  mounted() {
  },
  destroyed () {
    window.removeEventListener(scroll, this.handleScroll)
  },
  methods: {
    handleScroll() {
      var scrollTop = document.getElementById(pageId).scrollTop;
      this.listHeight.forEach((item, index) => {
        if (this.listHeight[index] < scrollTop && this.listHeight[index + 1] > scrollTop) {
          this.activtIndex = index
        }
      })
    },
    // 获取城市列表
    getCityList() {
      request({ url: `wxArea/search`, method: ‘get‘ }).then((res) => {
        let arr = [];
        for (let key in res) {
          let obj = {
            initial: null,
            list: null
          };
          obj.initial = res[key].initial;
          obj.list = res[key].list;
          arr.push(obj);
        }
        this.listData = arr;
        // 提取字母列表
        this.quickPanelData.forEach((item, index) => {
          const navItem = item.navName || item.title || "标题";
          this.letterList.push(navItem);
        });
        // 处理城市列表数据
        this.listData.forEach((item, index) => {
          this.letterList.push(item.initial);
        });
      })
    },
    //计算滚动条滚动的距离
    scrollSelect(index) {
      this.letter = this.letterList[index];
      this.fadeFlag = true;
      this.activtIndex = index;
      this.Timer = setTimeout(() => {
        this.fadeFlag = false;
      }, 1000);
      document.getElementById(pageId).scrollTop = this.listHeight[index];
    },
    _getHeight() {
      let rightItems = document.getElementsByClassName("base-wrap")
      let height = 0
      this.listHeight.push(height)
      for(let i = 0; i < rightItems.length; i++){
        let item = rightItems[i]
        height += item.clientHeight
        this.listHeight.push(height)
      }
    },
        //点击选择城市
    selectCity(name) {
      this.cityname= name;
      // this.$store.commit("changeCityName", name);
      // this.$router.push({ path: "/home" });
    },
    async onSelected(data) {
      //选择城市动态更新到首页
      this.cityname = data.city.value;
      // this.$store.commit("changeCityName", this.cityname);
      // this.$router.push({ path: "/home" });
    }
  }
};
</script>
<style lang="less" scoped>
.selectCityMain {
  width: 100%;
  height: 100vh;
  background-color: #f2f2f2;
  overflow-y: auto;
  position: relative;
  .letterBox {
    font-size: 0.44rem;
    position: fixed;
    top: 3.56rem;
    right: 0.42rem;
    color: #999;
    z-index: 2;
    p {
      width:0.64rem;
      height:0.64rem;
      text-align: center;
    }
    .active{
      border-radius: 50%;
      color: #fff;
      background: rgba(254,140,0,1);
    }
  }
  .now-letter {
    font-size: 60px;
    color: #ccc;
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate3d(-50%, -50%, 0);
    opacity: 0;
    z-index: 2;
    &.fadeIn {
      animation: fade 1s linear 0ms;
      opacity: 1;
    }
  }
  .now-sort {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    display: flex;
    align-items: center;
    box-sizing: border-box;
    font-size: 14px;
    padding: 10px;
    background: #ccc;
  }
  .hostCityBox {
    width: 100%;
    .base-wrap {
      overflow: hidden;
      .title {
        display: flex;
        align-items: center;
        box-sizing: border-box;
        font-size: 0.52rem;
        padding: 0.48rem 0.48rem 0.32rem;
        color: #999;
        // background: #ccc;
      }
      .panel {
        display: flex;
        flex-wrap: wrap;
        padding: 0 0.48rem;
        .item {
          width: 3.2rem;
          height: 1.44rem;
          font-size: 0.56rem;
          text-align: center;
          line-height: 1.44rem;
          background:rgba(255,255,255,1);
          border-radius:0.16rem;
          border:0.02rem solid rgba(229,229,229,1);
        }
        &::after {
          display: block;
          content: "";
          width: 200px;
          border: 1px solid transparent;
        }
      }
    }
  }
  .cityListBox {
    width: 100%;
    .title_bar {
      display: flex;
      align-items: center;
      box-sizing: border-box;
      font-size: 0.52rem;
      padding: 0.28rem 0.48rem;
      color: #999;
      // background: #ccc;
    }
    .panel {
      display: flex;
      flex-wrap: wrap;
      padding: 0 0.48rem;
      box-sizing: border-box;
      color: #333;
      background-color: #fff;
      .cityName {
        position: relative;
        font-size: 0.64rem;
        width: 100%;
        padding: 0.5rem 0;
        display: flex;
        align-items: center;
      }
    }
  }
}
</style>

技术图片

 技术图片

 

以上是关于模拟vant indexBar实现城市列表的主要内容,如果未能解决你的问题,请参考以下文章

揭秘 antd mobile “IndexBar” 的实现思路

揭秘 antd mobile “IndexBar” 的实现思路

揭秘 antd mobile “IndexBar” 的实现思路

APP开发-Vue3+Vant实现不同地区动态获取天气信息功能

APP开发-Vue3+Vant实现不同地区动态获取天气信息功能

APP开发-Vue3+Vant实现不同地区动态获取天气信息功能