vue中使用swiper实现滑动和字母检索

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/shelbyandfxj/article/details/83152158
<template>
  <div style="height: 100%;">
    <div class="search-div">
      <i class="search-icon"></i>
      <!--<input type="search" placeholder=""/>-->
      <input placeholder="" @input="handleInput"/>
    </div>
    <!--搜索结果-->
    <div class="search-result-div" v-if="hasResult">
      <ul>
        <li v-for="city in searchResultList" :id="city.id" @click="handleSelectCity(city)">{{city.name}}</li>
      </ul>
    </div>
    <div class="no-result" v-if="hasNoResult">抱歉,未找到你要搜索的内容</div>
    <div
      ref="cityContainer"
      class="swiper-container"
      style="height: calc(100% - 70px); overflow: hidden;"   // overflow:hidden避免滑动时溢出
      v-if="!hasResult && !hasNoResult"
    >
      <div
        ref="cityWrapper"
        class="swiper-wrapper"
      >
        <div class="cur-city-div block-list swiper-slide">
          <p>当前</p>
          <div class="grid">
            <div class="grid-cell">
              <p class="poi-text cur-city-text">
                {{curCityName}}
              </p>
            </div>
          </div>
        </div>
        <div class="pop-use-div block-list swiper-slide">
          <p>热点</p>
          <div class="grid">
            <div class="grid-cell" v-for="(item) in popCityList" @click="changeCity(item)">
              <p class="poi-text" :id="item.id">
                <!--<a class="loc-icon" :class="{'active':id == item.id}"></a>-->{{item.name}}</p>
            </div>
          </div>
        </div>
        <!--列表-->
        <div class="all-city-div block-list swiper-slide" v-for="cityList in allCityList" :id="cityList.id">
          <p class="city-list-anchor">{{cityList.name}}</p>
          <div class="city-block-div">
            <ul>
              <li v-for="city in cityList.data" @click="changeCity(city)">{{city.name}}</li>
            </ul>
          </div>
        </div>
      </div>
    </div>
    <div class="city-letter-div"
         @touchstart="touchStart"
         @touchmove="touchMove"
         @touchend="touchEnd"
         v-if="!hasResult && !hasNoResult"
    >
      <ul ref="cityLetterUl">
        <li v-for="letter in letterList">{{letter.name}}</li>
      </ul>
    </div>
    <div class="city-letter-select" v-if="letterClick">
      <p>{{letterName}}</p>
    </div>
  </div>
</template>

<script>

  import Swiper from 'swiper';

  export default {
    name: 'switchCity',
    components: {},
    data() {
      return {
        swiper: null,
        searchVal: '',
        letterClick: false,
        letterName: '',
        locCityName: '',
        hasResult: false,
        hasNoResult: false,
        startY: 0,           // 初始位置
        startIndex: 0,       // 初始的letterIndex
        disY: 0,             // 滑动距离
        searchResultList: [],      // 搜索结果
        allCityList: [{
          id: 2,
          name: 'A',
          data: [
            {
              index: 'A',
              name: '鞍山市',
              id: 'as'
            },
            {
              index: 'A',
              name: '安庆市',
              id: '86032424'
            },
            {
              index: 'A',
              name: '安阳市',
              id: 'ay'
            },
            {
              index: 'A',
              name: '阿拉善盟',
              id: 'alsm'
            },
            {
              index: 'A',
              name: '阿坝州',
              id: 'abz'
            },
            {
              index: 'A',
              name: '安顺市',
              id: 'ass'
            },
            {
              index: 'A',
              name: '阿里地区',
              id: 'aldq'
            },
            {
              index: 'A',
              name: '安康市',
              id: 'aks'
            },
            {
              index: 'A',
              name: '阿克苏地区',
              id: 'aksdq'
            }
          ]
        }, {
          id: 3,
          name: 'B',
          data: [
            {
              index: 'B',
              name: '鞍山市',
              id: 'as'
            },
            {
              index: 'B',
              name: '安庆市',
              id: 'aq'
            },
            {
              index: 'B',
              name: '安阳市',
              id: 'ay'
            },
            {
              index: 'B',
              name: '阿拉善盟',
              id: 'alsm'
            },
            {
              index: 'B',
              name: '阿坝州',
              id: 'abz'
            },
            {
              index: 'B',
              name: '安顺市',
              id: 'ass'
            },
            {
              index: 'B',
              name: '阿里地区',
              id: 'aldq'
            },
            {
              index: 'B',
              name: '安康市',
              id: 'aks'
            },
            {
              index: 'B',
              name: '安康市',
              id: 'aks'
            },
            {
              index: 'B',
              name: '阿克苏地区',
              id: 'aksdq'
            }
          ]
        }],
        letterList: [
          {
            name: '当前',
            id: '0'
          },
          {
            name: '热门',
            id: '1'
          },
          {
            name: 'A',
            id: '2'
          },
          {
            name: 'B',
            id: '3'
          },
          {
            name: 'C',
            id: '4'
          },
          {
            name: 'D',
            id: '5'
          },
          {
            name: 'E',
            id: 'E'
          },
          {
            name: 'F',
            id: 'F'
          },
          {
            name: 'G',
            id: 'G'
          },
          {
            name: 'H',
            id: 'H'
          },
          {
            name: 'I',
            id: 'I'
          },
          {
            name: 'J',
            id: 'J'
          },
          {
            name: 'K',
            id: 'K'
          },
          {
            name: 'L',
            id: 'L'
          },
          {
            name: 'M',
            id: 'M'
          },
          {
            name: 'N',
            id: 'N'
          },
          {
            name: 'O',
            id: 'O'
          },
          {
            name: 'P',
            id: 'P'
          },
          {
            name: 'Q',
            id: 'Q'
          },
          {
            name: 'R',
            id: 'R'
          },
          {
            name: 'S',
            id: 'S'
          },
          {
            name: 'T',
            id: 'T'
          },
          {
            name: 'U',
            id: 'U'
          },
          {
            name: 'V',
            id: 'V'
          },
          {
            name: 'W',
            id: 'W'
          },
          {
            name: 'X',
            id: 'X'
          },
          {
            name: 'Y',
            id: 'Y'
          },
          {
            name: 'Z',
            id: 'Z'
          }
        ]
      }
    },
    mounted() {
      this._initSwiper();
      for (let i = 0; i < this.commonCityList.length; i++) {
        if (this.$store.state.userCurBuildId === this.commonCityList[i].buildId) {
          this.locCityName = this.commonCityList[i].name;
        }
      }
      // this.locCityName = ;
    },
    computed: {
      buildId() {
        return this.$store.state.showCityId;
      },
      commonCityList() {
        return this.$store.state.commonCityList;
      },
      popCityList() {
        return this.$store.state.commonCityList;
      },
      curCityName() {
        return this.$store.state.showCityName;
      },
      isLocate() {
        return this.$store.state.userCurCityId;
      }
    },
    watch: {},
    methods: {
      _initSwiper() {
        this.swiper = new Swiper('.swiper-container', {
          // speed: 2000,
          observer: true,                   // 当改变swiper的样式(例如隐藏/显示)或者修改swiper的子元素时,自动初始化swiper
          observerParents: true,            // 将observe应用于Swiper的父元素
          freeMode: true,                   // 惯性滑动
          freeModeMomentum: true,           // 释放slider后会继续滑动
          freeModeMomentumBounceRatio: 0,   // 拖动时,至顶部或底部不继续滑动并回滚
          resistanceRatio: 0,               // 处于顶部或底部时,无法继续向下或向上拖动
          direction: 'vertical',            // 竖向滑动
          slidesPerView: "auto",            // 控制单屏显示的slider的数量,设置成auto,是让slider的高度自适应,如果是数字n,则单屏显示n个slider
          autoHeight: true,                  // wrapper和container会随着当前slide的高度而发生变化
          setWrapperSize: true,
          nested: true
        });
      },
      changeCity(item) {
        this.$store.commit('UPDATE_popPanel', 'normal');// 搜索面板恢复默认
        this.$store.commit('UPDATE_showCityId', item.id);
        this.$store.commit('UPDATE_showCityName', item.name);
        if (this.$store.state.userCurLocatedOpen) {
          this.jsBrigeUtil.stopUpdataCurLoc(this);
        }
        this.$router.push({name: 'Home'});
      },

      handleInput(ev) {
        ev = ev || event;
        let input = ev.target.value;
        this.search(input);
      },

      // 模糊搜索
      search(input) {
        let resultList = [];
        // let firstWord = input.slice(0, 1).toLowerCase();
        for (let i = 0; i < this.allCityList.length; i++) {
          /*if (!!Number(firstWord) || !(this.allCityList[i].name.toLowerCase() === firstWord)) {
            continue;
          }*/
          let cityList = this.allCityList[i].data;
          for (let j = 0; j < cityList.length; j++) {
            if (cityList[j].name.indexOf(input) < 0) {
              continue;
            }
            resultList.push({id: cityList[j].id, name: cityList[j].name});
          }
        }
        this.searchResultList = resultList;
        if (this.searchResultList.length > 0) {
          this.hasResult = true;
          this.hasNoResult = false;
        } else {
          this.hasResult = false;
          this.hasNoResult = true;
        }
      },

      handleSelectCity (item) {
        this.changeCity(item);
        this.hasResult = false;
        this.hasNoResult = false;
      },

      touchStart(ev) {
        ev = ev || event;
        if (ev.targetTouches.length > 1) return;
        this.startY = ev.targetTouches[0].clientY;   // 获取初始点
        if (ev.targetTouches[0].target.tagName.toLowerCase() != 'li') return;    // 当点击的节点不为li时直接跳出
        for (let i = 0; i < this.$refs.cityLetterUl.children.length; i++) {
          if (ev.targetTouches[0].target.textContent === this.$refs.cityLetterUl.children[i].innerText) {    // 因为无法获取到当前点击的是第几个li,因此通过比较li的textContent和当前点击的li,以找到点击的是第几个li
            this.startIndex = i;
            break;
          }
        }
        this.letterName = ev.targetTouches[0].target.textContent;
        this.swiper.slideTo(this.startIndex, 300, false);
        this.letterClick = true;
      },

      touchMove(ev) {
        ev = ev || event;
        if (ev.targetTouches.length > 1) return;
        this.disY = ev.targetTouches[0].clientY - this.startY;  // 计算移动了多少个li,每个li固定了高度为14px
        let index = 0;
        if (this.disY > 0) {
          index = this.startIndex + Math.floor(this.disY / 14);
        } else if (this.disY < 0) {
          index = this.startIndex + Math.floor(this.disY / 14);
        }
        if (index >= 0 && index < this.$refs.cityLetterUl.children.length) {  // 当在li的数量范围内才显示
          this.letterName = this.letterList[index].name;
          this.swiper.slideTo(index, 300, false);  // 模拟锚点
          this.letterClick = true;
        }
      },

      touchEnd(ev) {
        ev = ev || event;
        if (ev.changedTouches.length > 1) return;
        this.letterClick = false;
        this.letterName = '';
        this.startIndex = 0;
      },

      handleLetterClick(ev) {   // 点击li时执行并模拟锚点
        ev = ev || event;
        console.log('ev: ', ev);
        for (let i = 0; i < this.$refs.cityLetterUl.children.length; i++) {
          if (ev.target.text === this.$refs.cityLetterUl.children[i].innerText) {
            this.startIndex = i;
            break;
          }
        }
        this.letterName = this.$refs.cityLetterUl.children[this.startIndex].innerText;
        this.swiper.slideTo(this.startIndex, 300, false);
        this.letterClick = true;
        setTimeout(() => {
          this.letterClick = false;
        }, 300);
      }
    }
  }
</script>

<style scoped>
  /*搜索块 s*/
  .search-div {
    width: 94.4vw;
    height: 50px;
    margin: 10px auto 15px;
    border-radius: 5px;
    /*line-height: 36px;*/
    position: relative;
    overflow: hidden;
    background-color: #fff;
    box-shadow: 0 5px 10px 0 rgba(0, 0, 0, 0.10);
  }

  .search-div .search-icon {
    display: inline-block;
    width: 16px;
    height: 16px;
    background-image: url("./assets/[email protected]");
    background-size: 100% 100%;
    position: absolute;
    top: 12px;
    left: 20px;
  }

  .search-div input {
    width: 86.1vw;
    height: 40px;
    padding-top: 4px;
    box-sizing: border-box;
    font-size: 17px;
    background: #fff;
    border-top: 0;
    border-left: 0;
    border-right: 0;
    border-bottom: 1px solid hsla(0, 0%, 60.8%, .5);
    display: inherit;
    margin: 0 auto;
    padding-left: 30px;
    /*兼容ios*/
    border-radius: 0;
    /*解决ios不能输入问题*/
    -webkit-user-select: auto;
    /* 针对ios设置样式,去除ios下input的椭圆外框*/
    -webkit-appearance: none;
  }

  .search-div input:focus {
    outline: none;
  }

  /*搜索块 e*/

  /*常用div s*/
  .block-list {
    width: 94.4vw;
    font-size: 12px;
    color: #4A4A4A;
    margin: 0 auto 10px;
  }

  .block-list .grid {
    width: 100%;
    display: flex;
    flex-flow: row wrap;
    justify-content: flex-start;
    margin-top: 5px;
  }

  .block-list .grid .grid-cell {
    background-color: #fff;
    border-radius: 5px;
    box-sizing: border-box;
    width: 30.5%;
    margin: 5px 3.6vw 5px 0;
    overflow: hidden;
  }

  .block-list .grid .grid-cell:active {
    background-color: #e1e1e1;
  }

  .block-list .grid .grid-cell:nth-child(3n) {
    margin-right: 0;
  }

  .block-list .poi-text {
    height: 35px;
    line-height: 35px;
    font-size: 12px;
    color: #4A4A4A;
    text-align: center;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    padding: 0 10px;
  }

  .block-list .poi-text .loc-icon {
    width: 16px;
    height: 16px;
    background-image: url("./assets/[email protected]");
    background-size: 100% 100%;
    vertical-align: text-bottom;
    margin-right: 1px;
    display: none;
  }

  .block-list .poi-text .loc-icon.active {
    display: inline-block;
  }

  .city-list-contain-div {
    position: relative;
    overflow-y: hidden; /* 设置overflow-y为hidden,以避免原生的scroll影响根据手势滑动计算滚动距离 */
    background: transparent;
    /*解决安卓滑动页面时出现空白*/
    -webkit-backface-visibility: hidden;
    -webkit-transform: translate3d(0, 0, 0);
    height: calc(100% - 60px);
    margin-top: 10px;
  }

  
  .cur-city-div {
    /*margin: 0 auto;*/
  }

  .block-list .cur-city-text {
    color: #2A70FE;
  }

  /*  */
  .pop-use-div {
  }


  /* 站点列表和搜索结果列表 */
  .all-city-div, .search-result-div {
    width: 100%;
    color: #4a4a4a;
    margin: 0 auto;
  }

  .search-result-div {
    height: calc(100% - 75px);
  }

  .search-result-div ul {
    height: 100%;
    overflow-y: auto;
  }

  .all-city-div .city-list-anchor {
    width: 94.4vw;
    margin: 0 auto;
  }

  .all-city-div ul, .search-result-div ul {
    width: 100%;
    list-style: none;
    display: block;
    position: relative;
    background-color: #fff;
  }

  .all-city-div ul li, .search-result-div ul li {
    font-size: 15px;
    line-height: 40px;
    height: 40px;
    width: 94.4vw;
    margin: 0 auto;
    border-bottom: 1px solid rgba(155, 155, 155, .5);
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    box-sizing: border-box;
  }

  /* 没有搜索结果 */
  .no-result {
    box-sizing: border-box;
    padding: 10px;
    color: #4A4A4A;
    width: 100%;
    text-align: center;
    font-size: 12px;
  }

  /* 锚点 */
  .city-letter-div {
    z-index: 1;
    position: absolute;
    overflow: hidden;
    padding-right: 2.9vw;
    top: 50%;
    right: 0;
    transform: translateY(-50%);
    font-size: 10px;
    text-align: center;
  }

  .city-letter-div ul li {
    line-height: 14px;
    color: #2A70FE;
  }


  .city-letter-select {
    z-index: 1;
    width: 50px;
    height: 50px;
    background-color: #fff;
    color: #4A4A4A;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50% -50%);
    text-align: center;
    line-height: 50px;
  }


</style>

问题:在使用swiper的时候会遇到一个问题,因为效果是,滑到最底时便不能再向上滑动了,但是无论怎么滑动,都无法滑动到最底部,就无法看到最底部的数据。

呼呼呼~终于知道上面那个问题是为啥了,原来我给滑动的内容设置了相对父级高度100%了,忘记减掉了输入框所占的高度了。所以给滑动框内容高度减掉输入框所占据的高度就好了。

猜你喜欢

转载自blog.csdn.net/shelbyandfxj/article/details/83152158
今日推荐