• vue-cli 3.0 实现A-Z字母滑动选择城市列表


    项目地址:

    https://github.com/caochangkui/vue-cli3

    项目代码:

    城市列表首页:

    City.vue

    <template>
      <div id="city">
        <!-- <img src="/logo.png" alt="" height="10px"> -->
        <div class="word" v-show="showWord">
          <span>{{letter}}</span>
        </div>
        <div class="title">城市选择</div>
        <city-list
          :cities="cities"
          :hot="hotCities"
          :letter="letter"
        ></city-list>
        <city-alphabet
          :cities="cities"
          @change="handleLetterChange"
        ></city-alphabet>
      </div>
    </template>
    
    <script>
    import axios from 'axios'
    import CityList from './components/List'
    import CityAlphabet from './components/Alphabet'
    export default {
      name: 'City',
      components: {
        CityList,
        CityAlphabet
      },
      data () {
        return {
          showWord: false,
          cities: {},
          hotCities: [],
          letter: ''
        }
      },
      methods: {
        getCityInfo () {
          axios.get('/mock/city.json').then(this.handleGetCityInfoSucc)
        },
        handleGetCityInfoSucc (res) {
          console.log(res.data)
          res = res.data
          if (res.ret && res.data) {
            const data = res.data
            this.cities = data.cities
            this.hotCities = data.hotCities
          }
        },
        handleLetterChange (letter) {
          console.log(letter)
          this.letter = letter
          this.showWord = true
          setTimeout(() => {
            this.showWord = false
            console.log(this.showWord)
          }, 500)
        }
      },
      mounted () {
        this.getCityInfo()
      }
    }
    </script>
    
    <style scoped>
    .title {
      line-height: 40px;
      background: #10d1eb;
      color: #fff;
    }
    .word {
      position: fixed;
       100%;
      height: 100%;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      display: flex;
      justify-content: center;
      align-items: center;
      z-index: 99;
    }
    .word span {
      display: inline-block;
      height: 60px;
       60px;
      background: rgba(0, 0, 0, .2);
      display: flex;
      justify-content: center;
      align-items: center;
    }
    </style>
    
    

    城市列表组件:

    List.vue

    <template>
      <div class="list" ref="wrapper">
        <div>
          <div class="area">
            <div class="title">当前城市</div>
            <div class="button-list">
              <div class="button-wrapper">
                <div class="button">{{this.currentCity}}</div>
              </div>
            </div>
          </div>
          <div class="area">
            <div class="title">热门城市</div>
            <div class="button-list">
              <div
                class="button-wrapper"
                v-for="item in hot"
                :key="item.id"
                @click="handleCityClick(item.name)"
              >
                <div class="button">{{item.name}}</div>
              </div>
            </div>
          </div>
          <div
            class="area"
            v-for="(item, index) in cities"
            :key="index"
            :ref="index"
          >
            <div class="title">{{index}}</div>
            <div
              class="item-list"
              v-for="innerItem in item"
              :key=innerItem.id
              @click="handleCityClick(innerItem.name)"
              >
              <div class="item"> {{innerItem.name}} </div>
            </div>
          </div>
        </div>
      </div>
    </template>
    
    <script>
    import Bscroll from 'better-scroll'
    import { mapState, mapMutations } from 'vuex'
    export default {
      name: 'CityList',
      props: {
        hot: Array,
        cities: Object,
        letter: String
      },
      data () {
        return {
    
        }
      },
      computed: {
        ...mapState({
          currentCity: 'city'
        })
      },
      watch: {
        // 监听 Alphabet 中传过来的letter,如有变化,则滚动区域自动滚动到对应元素上
        letter () {
          if (this.letter) {
            const element = this.$refs[this.letter][0] // 获取对应字母的ref
            this.scroll.scrollToElement(element) // 利用better-scroll插件 滚动到指定元素element
            console.log(element)
          }
        }
      },
      methods: {
        ...mapMutations(['changeCity']),
        handleCityClick (city) {
          console.log(city)
          // this.$store.commit('changeCity', city) // 将参数city传给vuex中的mutations中的changeCity函数
          this.changeCity(city)
          this.$router.push('/') // 页面跳转 参考
        }
      },
      mounted () {
        this.scroll = new Bscroll(this.$refs.wrapper, {
          click: true
        })
      },
    
    }
    </script>
    
    <style scoped>
    .list {
      position: absolute;
      top: 40px;
      left: 0;
      right: 0;
      bottom: 0;
      overflow: hidden;
    }
    .title {
      line-height: 40px;
      background: #eee;
      padding-left: 10px;
      color: #666;
      font-size: 14px;
      text-align: left;
    }
    .button-list {
      overflow: hidden;
      padding: 10px 30px 10px 10px;
    }
    .button-wrapper {
      float: left;
       33.33%;
    }
    .button {
      margin: 4px;
      padding: 4px 0;
      text-align: center;
      border: 1px solid #ccc;
      border-radius: 4px;
      font-size: 14px;
      color: #555;
    }
    .item {
      line-height: 40px;
      padding-left: 16px;
      text-align: left;
      border-bottom: 1px solid #eee;
    }
    </style>
    
    

    字母检索组件:

    Alphabet.vue

    <template>
      <div class="list-wrapper">
        <ul class="list">
          <li class="item"
            v-for="item of letters"
            :key="item"
            :ref="item"
            @touchstart="handleTouchStart"
            @touchmove="handleTouchMove"
            @touchend="handleTouchEnd"
            @click="handleLetterClick"
          >{{item}}</li>
        </ul>
      </div>
    </template>
    
    <script>
    export default {
      name: 'CityAlphabet',
      props: {
        cities: Object
      },
      data () {
        return {
          touchStatus: false,
          startY: 0,
          timeer: null
        }
      },
      computed: {
        letters () {
          const letters = []
          for (let i in this.cities) {
            letters.push(i)
          }
          return letters
        }
      },
      // 生命周期函数
      updated () {
        this.startY = this.$refs['A'][0].offsetTop // A字母距离滚动条顶部距离
        console.log('updated---> ', this.startY)
      },
      methods: {
        handleLetterClick (e) {
          this.$emit('change', e.target.innerText)
          console.log(1)
        },
        handleTouchStart () {
          console.log('开始滑动')
          this.touchStatus = true
        },
        handleTouchMove (e) {
          if (this.touchStatus) {
            if (this.timeer) {
              clearTimeout(this.timeer)
            }
            this.timeer = setTimeout(() => {
              console.log(e.touches[0])
              const touchY = e.touches[0].clientY - 40 // 手指触摸当前位置距离视口顶部的距离减去40(40指滚动区域最上边和页面顶部之间的距离)
              const index = Math.floor((touchY - this.startY) / 26) // 手指触摸当前位置所在的字母索引(26指单个字母的高度)
              if (index >= 0 && index < this.letters.length) {
                this.$emit('change', this.letters[index])
              }
            }, 16)
          }
        },
        handleTouchEnd () {
          this.touchStatus = false
        }
      }
    }
    </script>
    
    <style scoped>
      .list {
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        position: absolute;
        right: 0;
        top: 40px;
        bottom: 0;
         30px;
        list-style: none;
        background: rgba(0, 0, 0, .2);
        margin: 0;
        padding: 0;
        z-index: 999;
      }
      .item {
        line-height: 24px;
        color: #068b9c;
        font-size: 14px;
        text-align: center;
         100%;
      }
    
    </style>
    
    

    通过vuex管理已选城市:

    import Vue from 'vue'
    import Vuex from 'vuex'
    
    Vue.use(Vuex)
    
    let defaultCity = '北京'
    
    try {
        if (localStorage.city) {
          defaultCity = localStorage.city
        }
      } catch (e) {e}
    
    const state = {
        count: 1,
        city: defaultCity
    }
    
    const mutations = { 
        changeCity (state, city) {
            state.city = city
            try {
              localStorage.city = city
            } catch (e) {e}
        }
    }
    
    const actions = { 
    
    }
    
    export default new Vuex.Store({
        state,
        mutations,
        actions
    })
    
  • 相关阅读:
    .c 文件取为.o文件
    wildcard 处理全部文件
    专家解读Linux操作系统内核中的GCC特性
    Yeoman:适合现代Web应用的现代工作流
    【转】nodejs
    node.js
    2019暑假集训 种树
    2019.6.5 NOIP2014 day2 t2 寻找道路
    2019.6.1 最优贸易
    2019.5.11 海淀区赛之杯子
  • 原文地址:https://www.cnblogs.com/cckui/p/10265833.html
Copyright © 2020-2023  润新知