Vue2.5开发去哪儿网App 城市列表开发之 兄弟组件间联动及列表性能优化

一,  兄弟组件间联动

1.  点击城市字母,左侧对应显示

给遍历的 字母 添加一个点击事件:

Alphabet.vue

@click="handleLetterClick"
    handleLetterClick (e) {
//获取对应的字母
this.$emit('change', e.target.innerHTML) }

在 父组件City.vue 中,监听

<city-alphabet :cities="cities" @change="handleLetterChange"></city-alphabet>
    handleLetterChange (letter) {
      this.letter = letter
    }

然后转发给子CityList组件:

    <city-list :letter="letter"></city-list>

CityList组件,监听:

添加 ref属性      

<div class="area" v-for="(city,key) in cities" :key="key" :ref="key"> <div class="title border-topbottom">{{key}}</div> <div class="item-list"> <div class="item border-bottom" v-for="c in city" :key="c.id">{{c.name}}</div> </div> </div>

 

 props: ['letter'],
  watch: {
    letter () {
      if (this.letter) {
        const element = this.$refs[this.letter][0]
// better-scrool方法,滚动区自动滚动到元素上
this.scroll.scrollToElement(element) } }

 

 

2.  拖动城市字母表,左侧城市对应滚动

 给Alphabet.vue 字母列表绑定事件:

<ul class="list">
<li class="item" v-for="item in letters" :key="item"
@click="handleLetterClick"
@touchstart="handleTouchStart"
@touchmove="handleTouchMove"
@touchend="handleTouchEnd"
:ref = 'item'
>{{item}}
</li>
</ul>

事件说明:

touchstart : 触摸开始(手指放在触摸屏上)

touchmove : 拖动(手指在触摸屏上移动)

touchend : 触摸结束(手指从触摸屏上移开)

当前第几个字母   = (触摸处浏览器页面的垂直坐标  -  A 字母距离搜索栏底部的距离) / 每个字母的高度

  methods: {
      handleTouchStart () {
//滑动开始
this.touchStatus = true }, handleTouchMove (e) { if (this.touchStatus) { // A 字母距离搜索栏底部的距离 const startY = this.$refs['A'][0].offsetTop
      // 79 为:顶部搜索栏 的高度 const touchY
= e.touches[0].clientY - 79 const index = Math.floor(touchY - startY) / 20 if (index >= 0 && index < this.letters.length) { this.$emit('change', this.letters[index]) } } }, handleTouchEnd () {
     // 滑动结束
this.touchStatus = false } }
<template>
  <div>
    <ul class="list">
      <li class="item" v-for="item in letters" :key="item"
          @click="handleLetterClick"
          @touchstart="handleTouchStart"
          @touchmove="handleTouchMove"
          @touchend="handleTouchEnd"
          :ref = 'item'
      >{{item}}
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  name: 'CityAlphabet',
  props: ['cities'],
  data () {
    return {
      touchStatus: false
    }
  },
  computed: {
    letters () {
      const letters = []
      for (let i in this.cities) {
        letters.push(i)
      }
      return letters
    }
  },
  methods: {
    handleLetterClick (e) {
      this.$emit('change', e.target.innerHTML)
    },
    handleTouchStart () {
      this.touchStatus = true
    },
    handleTouchMove (e) {
      if (this.touchStatus) {
        // A 字母距离搜索栏底部的距离
        const startY = this.$refs['A'][0].offsetTop
        const touchY = e.touches[0].clientY - 79
        const index = Math.floor(touchY - startY) / 20
        if (index >= 0 && index < this.letters.length) {
          this.$emit('change', this.letters[index])
        }
      }
    },
    handleTouchEnd () {
      this.touchStatus = false
    }
  }
}
</script>

<style lang="stylus" scoped>
  @import "~styles/varibles.styl"
  .list
    position absolute
    right 0
    top 1.58rem
    bottom 0
    display flex
    width .4rem
    flex-direction column
    justify-content center
    .item
      text-align center
      line-height .4rem
      color $bgColor
</style>
Alphabet.vue

二,列表切换性能优化

1.  滚动的优化

 滚动重复执行运算:

this.$refs['A'][0].offsetTop

在 data 中定义 变量  

  data () {
    return {
      startY: 0
    }
  }

添加生命周期钩子 updated:
  updated () {
    this.startY = this.$refs['A'][0].offsetTop
  }

handleTouchMove (e) { if (this.touchStatus) { const touchY = e.touches[0].clientY - 79 const index = Math.floor(touchY - this.startY) / 20 if (index >= 0 && index < this.letters.length) { this.$emit('change', this.letters[index]) } } }

2. 节流限制 函数   handleTouchMove()  执行的频率

   data中  定义   timer: null

  data () {
    return {
      touchStatus: false,
      startY: 0,
      timer: null
    }

函数的改动:

    handleTouchMove (e) {
      if (this.touchStatus) {
        if (this.timer) {
          clearTimeout(this.time)
        }
        this.timer = setTimeout(() => {
          const touchY = e.touches[0].clientY - 79
          const index = Math.floor(touchY - this.startY) / 20
          if (index >= 0 && index < this.letters.length) {
            this.$emit('change', this.letters[index])
          }
        }, 16)
      }
    }

 

项目地址https://github.com/1417766861/Vue2.5-App/tree/master/Travel

 

posted @ 2019-02-26 16:35  最美的烟火  阅读(772)  评论(1编辑  收藏  举报