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>
二,列表切换性能优化
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